From 57caa9d28f1a4d85db6a4bda71e9c78f4f84dd76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20R=C3=A9?= Date: Thu, 4 Dec 2025 16:09:36 +0400 Subject: [PATCH] Move route utils to packages/routes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Émile Ré --- apps/console/package.json | 3 +- apps/console/src/routes.tsx | 82 ++----------------- apps/console/src/routes/assetRoutes.ts | 10 +-- apps/console/src/routes/auditRoutes.ts | 8 +- .../src/routes/continualImprovementRoutes.ts | 10 +-- apps/console/src/routes/dataRoutes.ts | 10 +-- apps/console/src/routes/documentsRoutes.ts | 12 +-- apps/console/src/routes/frameworkRoutes.ts | 8 +- apps/console/src/routes/measureRoutes.ts | 14 ++-- apps/console/src/routes/meetingsRoutes.ts | 10 +-- .../console/src/routes/nonconformityRoutes.ts | 10 +-- apps/console/src/routes/obligationRoutes.ts | 12 +-- apps/console/src/routes/peopleRoutes.ts | 12 +-- .../src/routes/processingActivityRoutes.ts | 10 +-- apps/console/src/routes/riskRoutes.ts | 22 ++--- apps/console/src/routes/snapshotsRoutes.ts | 6 +- apps/console/src/routes/taskRoutes.ts | 4 +- apps/console/src/routes/trustCenterRoutes.ts | 18 ++-- apps/console/src/routes/vendorRoutes.ts | 34 ++++---- package-lock.json | 34 ++++++-- packages/helpers/src/routes.tsx | 40 +++++++++ .../helpers/src}/useDelayedEffect.ts | 0 packages/hooks/src/useCleanup.ts | 19 +++++ packages/routes/package.json | 27 ++++++ packages/routes/src/appRoute.tsx | 30 +++++++ packages/routes/src/index.ts | 2 + packages/routes/src/relay.tsx | 35 ++++++++ packages/routes/tsconfig.json | 6 ++ 28 files changed, 299 insertions(+), 189 deletions(-) create mode 100644 packages/helpers/src/routes.tsx rename {apps/console/src/hooks => packages/helpers/src}/useDelayedEffect.ts (100%) create mode 100644 packages/hooks/src/useCleanup.ts create mode 100644 packages/routes/package.json create mode 100644 packages/routes/src/appRoute.tsx create mode 100644 packages/routes/src/index.ts create mode 100644 packages/routes/src/relay.tsx create mode 100644 packages/routes/tsconfig.json diff --git a/apps/console/package.json b/apps/console/package.json index dfd65e42b..8f0b5d456 100644 --- a/apps/console/package.json +++ b/apps/console/package.json @@ -13,10 +13,11 @@ }, "dependencies": { "@hookform/resolvers": "^5.0.1", - "@probo/helpers": "1.0.0", + "@probo/helpers": "^1.0.0", "@probo/hooks": "1.0.0", "@probo/i18n": "1.0.0", "@probo/react-lazy": "1.0.0", + "@probo/routes": "^1.0.0", "@probo/ui": "1.0.0", "@probo/vendors": "0.0.1", "@tanstack/react-query": "^5.76.1", diff --git a/apps/console/src/routes.tsx b/apps/console/src/routes.tsx index dc1092979..f7d15b129 100644 --- a/apps/console/src/routes.tsx +++ b/apps/console/src/routes.tsx @@ -2,15 +2,11 @@ import { createBrowserRouter, Navigate, redirect, - useLoaderData, useRouteError, - type LoaderFunction, - type LoaderFunctionArgs, - type RouteObject, } from "react-router"; import { MainLayout } from "./layouts/MainLayout"; import { AuthLayout, CenteredLayout, CenteredLayoutSkeleton } from "@probo/ui"; -import { Fragment, Suspense, type ComponentType, type LazyExoticComponent } from "react"; +import { Fragment } from "react"; import { relayEnvironment, UnAuthenticatedError, @@ -18,8 +14,7 @@ import { ForbiddenError, } from "./providers/RelayProviders"; import { PageSkeleton } from "./components/skeletons/PageSkeleton.tsx"; -import { loadQuery, type EnvironmentProviderOptions, type PreloadedQuery } from "react-relay"; -import { useCleanup } from "./hooks/useDelayedEffect.ts"; +import { loadQuery } from "react-relay"; import { riskRoutes } from "./routes/riskRoutes.ts"; import { measureRoutes } from "./routes/measureRoutes.ts"; import { documentsRoutes } from "./routes/documentsRoutes.ts"; @@ -40,42 +35,7 @@ import { snapshotsRoutes } from "./routes/snapshotsRoutes.ts"; import { continualImprovementRoutes } from "./routes/continualImprovementRoutes.ts"; import { processingActivityRoutes } from "./routes/processingActivityRoutes.ts"; import { lazy } from "@probo/react-lazy"; -import type { OperationType } from "relay-runtime"; - -export function withQueryRef< - TQuery extends OperationType, - TEnvironmentProviderOptions = EnvironmentProviderOptions ->( - Component: LazyExoticComponent }>>, -) { - return () => { - const { queryRef, dispose } = useLoaderData(); - - useCleanup(dispose, 1000); - - return - } -} - -export function loaderFromQueryLoader< - TQuery extends OperationType, - TEnvironmentProviderOptions = EnvironmentProviderOptions ->( - queryLoader: (params: Record) => PreloadedQuery -): LoaderFunction { - return ({ params }: LoaderFunctionArgs) => { - const query = queryLoader(params as Record); - return { - queryRef: query, - dispose: query.dispose, - }; - } -} - -export type AppRoute = Omit & { - children?: AppRoute[]; - fallback?: ComponentType; -} +import { loaderFromQueryLoader, routeFromAppRoute, withQueryRef, type AppRoute } from "@probo/routes"; /** * Top level error boundary @@ -132,7 +92,7 @@ const routes = [ { path: "/", Component: CenteredLayout, - fallback: CenteredLayoutSkeleton, + Fallback: CenteredLayoutSkeleton, ErrorBoundary: ErrorBoundary, children: [ { @@ -171,7 +131,7 @@ const routes = [ }, { path: "settings", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader( ({ organizationId }) => loadQuery(relayEnvironment, organizationViewQuery, { @@ -234,34 +194,4 @@ const routes = [ }, ] satisfies AppRoute[]; -/** - * Wrap components with suspense to handle lazy loading & relay loading states - */ -function routeTransformer({ - Component, - fallback: FallbackComponent, - children, - ...rest -}: AppRoute): RouteObject { - let route: RouteObject = { ...rest }; - - if (Component && FallbackComponent) { - const OriginalComponent = Component as ComponentType; - - route = { - ...route, - Component: () => ( - }> - - - ), - }; - } - - return { - ...route, - children: children?.map(routeTransformer), - } as RouteObject; -} - -export const router = createBrowserRouter(routes.map(routeTransformer)); +export const router = createBrowserRouter(routes.map(routeFromAppRoute)); diff --git a/apps/console/src/routes/assetRoutes.ts b/apps/console/src/routes/assetRoutes.ts index ed1f42cf9..cdae67179 100644 --- a/apps/console/src/routes/assetRoutes.ts +++ b/apps/console/src/routes/assetRoutes.ts @@ -5,12 +5,12 @@ import { lazy } from "@probo/react-lazy"; import { assetsQuery, assetNodeQuery } from "../hooks/graph/AssetGraph"; import type { AssetGraphListQuery } from "/hooks/graph/__generated__/AssetGraphListQuery.graphql"; import type { AssetGraphNodeQuery } from "/hooks/graph/__generated__/AssetGraphNodeQuery.graphql"; -import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; export const assetRoutes = [ { path: "assets", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, assetsQuery, { organizationId: organizationId, @@ -21,7 +21,7 @@ export const assetRoutes = [ }, { path: "snapshots/:snapshotId/assets", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId, snapshotId }) => loadQuery(relayEnvironment, assetsQuery, { organizationId: organizationId, @@ -32,7 +32,7 @@ export const assetRoutes = [ }, { path: "assets/:assetId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ assetId }) => loadQuery(relayEnvironment, assetNodeQuery, { assetId }), ), @@ -42,7 +42,7 @@ export const assetRoutes = [ }, { path: "snapshots/:snapshotId/assets/:assetId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ assetId }) => loadQuery(relayEnvironment, assetNodeQuery, { assetId }), ), diff --git a/apps/console/src/routes/auditRoutes.ts b/apps/console/src/routes/auditRoutes.ts index f253d1d40..e84f79f4e 100644 --- a/apps/console/src/routes/auditRoutes.ts +++ b/apps/console/src/routes/auditRoutes.ts @@ -5,12 +5,12 @@ import { lazy } from "@probo/react-lazy"; import { auditsQuery, auditNodeQuery } from "../hooks/graph/AuditGraph"; import type { AuditGraphListQuery } from "/hooks/graph/__generated__/AuditGraphListQuery.graphql"; import type { AuditGraphNodeQuery } from "/hooks/graph/__generated__/AuditGraphNodeQuery.graphql"; -import { loaderFromQueryLoader, withQueryRef } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; export const auditRoutes = [ { path: "audits", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, auditsQuery, { organizationId }), ), @@ -20,7 +20,7 @@ export const auditRoutes = [ }, { path: "audits/:auditId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ auditId }) => loadQuery(relayEnvironment, auditNodeQuery, { auditId }), ), @@ -28,4 +28,4 @@ export const auditRoutes = [ () => import("/pages/organizations/audits/AuditDetailsPage") )), }, -]; +] satisfies AppRoute[]; diff --git a/apps/console/src/routes/continualImprovementRoutes.ts b/apps/console/src/routes/continualImprovementRoutes.ts index 4ca117d74..fffef70ae 100644 --- a/apps/console/src/routes/continualImprovementRoutes.ts +++ b/apps/console/src/routes/continualImprovementRoutes.ts @@ -5,12 +5,12 @@ import { lazy } from "@probo/react-lazy"; import { continualImprovementsQuery, continualImprovementNodeQuery } from "/hooks/graph/ContinualImprovementGraph"; import type { ContinualImprovementGraphListQuery } from "/hooks/graph/__generated__/ContinualImprovementGraphListQuery.graphql"; import type { ContinualImprovementGraphNodeQuery } from "/hooks/graph/__generated__/ContinualImprovementGraphNodeQuery.graphql"; -import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; export const continualImprovementRoutes = [ { path: "continual-improvements", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, continualImprovementsQuery, { organizationId, @@ -23,7 +23,7 @@ export const continualImprovementRoutes = [ }, { path: "snapshots/:snapshotId/continual-improvements", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId, snapshotId }) => loadQuery(relayEnvironment, continualImprovementsQuery, { organizationId, @@ -36,7 +36,7 @@ export const continualImprovementRoutes = [ }, { path: "continual-improvements/:improvementId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ improvementId }) => loadQuery(relayEnvironment, continualImprovementNodeQuery, { continualImprovementId: improvementId!, @@ -48,7 +48,7 @@ export const continualImprovementRoutes = [ }, { path: "snapshots/:snapshotId/continual-improvements/:improvementId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ improvementId }) => loadQuery(relayEnvironment, continualImprovementNodeQuery, { continualImprovementId: improvementId!, diff --git a/apps/console/src/routes/dataRoutes.ts b/apps/console/src/routes/dataRoutes.ts index f93b06031..379303079 100644 --- a/apps/console/src/routes/dataRoutes.ts +++ b/apps/console/src/routes/dataRoutes.ts @@ -5,12 +5,12 @@ import { lazy } from "@probo/react-lazy"; import { dataQuery, datumNodeQuery } from "../hooks/graph/DatumGraph"; import type { DatumGraphListQuery } from "/hooks/graph/__generated__/DatumGraphListQuery.graphql"; import type { DatumGraphNodeQuery } from "/hooks/graph/__generated__/DatumGraphNodeQuery.graphql"; -import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; export const dataRoutes = [ { path: "data", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, dataQuery, { organizationId: organizationId, @@ -23,7 +23,7 @@ export const dataRoutes = [ }, { path: "snapshots/:snapshotId/data", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId, snapshotId }) => loadQuery(relayEnvironment, dataQuery, { organizationId, @@ -36,7 +36,7 @@ export const dataRoutes = [ }, { path: "data/:dataId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ dataId }) => loadQuery(relayEnvironment, datumNodeQuery, { dataId }), ), @@ -46,7 +46,7 @@ export const dataRoutes = [ }, { path: "snapshots/:snapshotId/data/:dataId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ dataId }) => loadQuery(relayEnvironment, datumNodeQuery, { dataId }), ), diff --git a/apps/console/src/routes/documentsRoutes.ts b/apps/console/src/routes/documentsRoutes.ts index c51584c1d..e0fb51ce5 100644 --- a/apps/console/src/routes/documentsRoutes.ts +++ b/apps/console/src/routes/documentsRoutes.ts @@ -7,7 +7,7 @@ import { PageSkeleton } from "/components/skeletons/PageSkeleton"; import { redirect, type LoaderFunctionArgs } from "react-router"; import { lazy } from "@probo/react-lazy"; import { LinkCardSkeleton } from "/components/skeletons/LinkCardSkeleton"; -import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; import type { DocumentGraphListQuery } from "/hooks/graph/__generated__/DocumentGraphListQuery.graphql"; import type { DocumentGraphNodeQuery } from "/hooks/graph/__generated__/DocumentGraphNodeQuery.graphql"; @@ -26,7 +26,7 @@ const documentTabs = (prefix: string) => { }, { path: `${prefix}description`, - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import( @@ -36,7 +36,7 @@ const documentTabs = (prefix: string) => { }, { path: `${prefix}controls`, - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("../pages/organizations/documents/tabs/DocumentControlsTab"), @@ -44,7 +44,7 @@ const documentTabs = (prefix: string) => { }, { path: `${prefix}signatures`, - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("../pages/organizations/documents/tabs/DocumentSignaturesTab"), @@ -56,7 +56,7 @@ const documentTabs = (prefix: string) => { export const documentsRoutes = [ { path: "documents", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, documentsQuery, { organizationId: organizationId! }), ), @@ -66,7 +66,7 @@ export const documentsRoutes = [ }, { path: "documents/:documentId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ documentId }) => loadQuery(relayEnvironment, documentNodeQuery, { documentId: documentId! }), ), diff --git a/apps/console/src/routes/frameworkRoutes.ts b/apps/console/src/routes/frameworkRoutes.ts index 06522eebf..d3c795b98 100644 --- a/apps/console/src/routes/frameworkRoutes.ts +++ b/apps/console/src/routes/frameworkRoutes.ts @@ -9,7 +9,7 @@ import { import { Fragment } from "react"; import { lazy } from "@probo/react-lazy"; import { ControlSkeleton } from "../components/skeletons/ControlSkeleton"; -import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; import type { FrameworkGraphListQuery } from "/hooks/graph/__generated__/FrameworkGraphListQuery.graphql"; import type { FrameworkGraphNodeQuery } from "/hooks/graph/__generated__/FrameworkGraphNodeQuery.graphql"; import type { FrameworkGraphControlNodeQuery } from "/hooks/graph/__generated__/FrameworkGraphControlNodeQuery.graphql"; @@ -17,7 +17,7 @@ import type { FrameworkGraphControlNodeQuery } from "/hooks/graph/__generated__/ export const frameworkRoutes = [ { path: "frameworks", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, frameworksQuery, { organizationId: organizationId! }), ), @@ -27,7 +27,7 @@ export const frameworkRoutes = [ }, { path: "frameworks/:frameworkId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ frameworkId }) => loadQuery(relayEnvironment, frameworkNodeQuery, { frameworkId: frameworkId! }), ), @@ -41,7 +41,7 @@ export const frameworkRoutes = [ }, { path: "controls/:controlId", - fallback: ControlSkeleton, + Fallback: ControlSkeleton, loader: loaderFromQueryLoader(({ controlId }) => loadQuery(relayEnvironment, frameworkControlNodeQuery, { controlId: controlId! }), ), diff --git a/apps/console/src/routes/measureRoutes.ts b/apps/console/src/routes/measureRoutes.ts index 3a460dc0a..00d4307e4 100644 --- a/apps/console/src/routes/measureRoutes.ts +++ b/apps/console/src/routes/measureRoutes.ts @@ -6,14 +6,14 @@ import { PageSkeleton } from "/components/skeletons/PageSkeleton"; import { redirect } from "react-router"; import { lazy } from "@probo/react-lazy"; import { LinkCardSkeleton } from "/components/skeletons/LinkCardSkeleton"; -import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; import type { MeasureGraphListQuery } from "/hooks/graph/__generated__/MeasureGraphListQuery.graphql"; import type { MeasureGraphNodeQuery } from "/hooks/graph/__generated__/MeasureGraphNodeQuery.graphql"; export const measureRoutes = [ { path: "measures", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, measuresQuery, { organizationId: organizationId! }), ), @@ -27,7 +27,7 @@ export const measureRoutes = [ }, { path: "measures/:measureId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ measureId }) => loadQuery(relayEnvironment, measureNodeQuery, { measureId: measureId! }), ), @@ -42,21 +42,21 @@ export const measureRoutes = [ }, { path: "risks", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/measures/tabs/MeasureRisksTab.tsx") ), }, { path: "tasks", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/measures/tabs/MeasureTasksTab.tsx") ), }, { path: "controls", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/measures/tabs/MeasureControlsTab.tsx") @@ -64,7 +64,7 @@ export const measureRoutes = [ }, { path: "evidences/:evidenceId?", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/measures/tabs/MeasureEvidencesTab.tsx") diff --git a/apps/console/src/routes/meetingsRoutes.ts b/apps/console/src/routes/meetingsRoutes.ts index dfd1dc5fc..24cdce530 100644 --- a/apps/console/src/routes/meetingsRoutes.ts +++ b/apps/console/src/routes/meetingsRoutes.ts @@ -9,7 +9,7 @@ import { lazy } from "@probo/react-lazy"; import { LinkCardSkeleton } from "/components/skeletons/LinkCardSkeleton"; import type { MeetingGraphListQuery } from "/hooks/graph/__generated__/MeetingGraphListQuery.graphql"; import type { MeetingGraphNodeQuery } from "/hooks/graph/__generated__/MeetingGraphNodeQuery.graphql"; -import { loaderFromQueryLoader, withQueryRef } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; const meetingTabs = (prefix: string) => { return [ @@ -24,7 +24,7 @@ const meetingTabs = (prefix: string) => { }, { path: `${prefix}minutes`, - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import( @@ -38,7 +38,7 @@ const meetingTabs = (prefix: string) => { export const meetingsRoutes = [ { path: "meetings", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, meetingsQuery, { organizationId }), ), @@ -48,7 +48,7 @@ export const meetingsRoutes = [ }, { path: "meetings/:meetingId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ meetingId }) => loadQuery(relayEnvironment, meetingNodeQuery, { meetingId }), ), @@ -57,5 +57,5 @@ export const meetingsRoutes = [ )), children: [...meetingTabs("")], }, -]; +] satisfies AppRoute[]; diff --git a/apps/console/src/routes/nonconformityRoutes.ts b/apps/console/src/routes/nonconformityRoutes.ts index 473a21bb4..1e340c42c 100644 --- a/apps/console/src/routes/nonconformityRoutes.ts +++ b/apps/console/src/routes/nonconformityRoutes.ts @@ -5,12 +5,12 @@ import { lazy } from "@probo/react-lazy"; import { nonconformitiesQuery, nonconformityNodeQuery } from "../hooks/graph/NonconformityGraph"; import type { NonconformityGraphListQuery } from "/hooks/graph/__generated__/NonconformityGraphListQuery.graphql"; import type { NonconformityGraphNodeQuery } from "/hooks/graph/__generated__/NonconformityGraphNodeQuery.graphql"; -import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; export const nonconformityRoutes = [ { path: "nonconformities", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, nonconformitiesQuery, { organizationId, @@ -23,7 +23,7 @@ export const nonconformityRoutes = [ }, { path: "snapshots/:snapshotId/nonconformities", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId, snapshotId }) => loadQuery(relayEnvironment, nonconformitiesQuery, { organizationId, @@ -36,7 +36,7 @@ export const nonconformityRoutes = [ }, { path: "nonconformities/:nonconformityId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ nonconformityId }) => loadQuery(relayEnvironment, nonconformityNodeQuery, { nonconformityId, @@ -48,7 +48,7 @@ export const nonconformityRoutes = [ }, { path: "snapshots/:snapshotId/nonconformities/:nonconformityId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ nonconformityId }) => loadQuery(relayEnvironment, nonconformityNodeQuery, { nonconformityId: nonconformityId diff --git a/apps/console/src/routes/obligationRoutes.ts b/apps/console/src/routes/obligationRoutes.ts index 18de5253d..0882c1c17 100644 --- a/apps/console/src/routes/obligationRoutes.ts +++ b/apps/console/src/routes/obligationRoutes.ts @@ -5,12 +5,12 @@ import { lazy } from "@probo/react-lazy"; import { obligationsQuery, obligationNodeQuery } from "/hooks/graph/ObligationGraph"; import type { ObligationGraphListQuery } from "/hooks/graph/__generated__/ObligationGraphListQuery.graphql"; import type { ObligationGraphNodeQuery } from "/hooks/graph/__generated__/ObligationGraphNodeQuery.graphql"; -import { loaderFromQueryLoader, withQueryRef } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; export const obligationRoutes = [ { path: "obligations", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, obligationsQuery, { organizationId, @@ -23,7 +23,7 @@ export const obligationRoutes = [ }, { path: "snapshots/:snapshotId/obligations", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId, snapshotId }) => loadQuery(relayEnvironment, obligationsQuery, { organizationId, @@ -36,7 +36,7 @@ export const obligationRoutes = [ }, { path: "obligations/:obligationId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ obligationId }) => loadQuery(relayEnvironment, obligationNodeQuery, { obligationId, @@ -48,7 +48,7 @@ export const obligationRoutes = [ }, { path: "snapshots/:snapshotId/obligations/:obligationId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ obligationId }) => loadQuery(relayEnvironment, obligationNodeQuery, { obligationId, @@ -58,4 +58,4 @@ export const obligationRoutes = [ () => import("/pages/organizations/obligations/ObligationDetailsPage") )), }, -]; +] satisfies AppRoute[]; diff --git a/apps/console/src/routes/peopleRoutes.ts b/apps/console/src/routes/peopleRoutes.ts index a85c73fd1..f9b97626c 100644 --- a/apps/console/src/routes/peopleRoutes.ts +++ b/apps/console/src/routes/peopleRoutes.ts @@ -7,14 +7,14 @@ import { peopleNodeQuery, } from "/hooks/graph/PeopleGraph"; import { LinkCardSkeleton } from "/components/skeletons/LinkCardSkeleton"; -import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; import type { PeopleGraphPaginatedQuery } from "/hooks/graph/__generated__/PeopleGraphPaginatedQuery.graphql"; import type { PeopleGraphNodeQuery } from "/hooks/graph/__generated__/PeopleGraphNodeQuery.graphql"; export const peopleRoutes = [ { path: "people", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, paginatedPeopleQuery, { organizationId: organizationId! }), ), @@ -22,7 +22,7 @@ export const peopleRoutes = [ }, { path: "people/:peopleId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ peopleId }) => loadQuery(relayEnvironment, peopleNodeQuery, { peopleId: peopleId! }), ), @@ -32,21 +32,21 @@ export const peopleRoutes = [ children: [ { path: "tasks", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/people/tabs/PeopleTasksTab") ), }, { path: "role", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/people/tabs/PeopleRoleTab") ), }, { path: "profile", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/people/tabs/PeopleProfileTab") ), diff --git a/apps/console/src/routes/processingActivityRoutes.ts b/apps/console/src/routes/processingActivityRoutes.ts index 25462b861..e6b7e52e4 100644 --- a/apps/console/src/routes/processingActivityRoutes.ts +++ b/apps/console/src/routes/processingActivityRoutes.ts @@ -3,14 +3,14 @@ import { relayEnvironment } from "/providers/RelayProviders"; import { PageSkeleton } from "/components/skeletons/PageSkeleton"; import { lazy } from "@probo/react-lazy"; import { processingActivitiesQuery, processingActivityNodeQuery } from "/hooks/graph/ProcessingActivityGraph"; -import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; import type { ProcessingActivityGraphListQuery } from "/hooks/graph/__generated__/ProcessingActivityGraphListQuery.graphql"; import type { ProcessingActivityGraphNodeQuery } from "/hooks/graph/__generated__/ProcessingActivityGraphNodeQuery.graphql"; export const processingActivityRoutes = [ { path: "processing-activities", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, processingActivitiesQuery, { organizationId: organizationId!, @@ -23,7 +23,7 @@ export const processingActivityRoutes = [ }, { path: "snapshots/:snapshotId/processing-activities", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId, snapshotId }) => loadQuery(relayEnvironment, processingActivitiesQuery, { organizationId: organizationId!, @@ -36,7 +36,7 @@ export const processingActivityRoutes = [ }, { path: "processing-activities/:activityId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ activityId }) => loadQuery(relayEnvironment, processingActivityNodeQuery, { processingActivityId: activityId!, @@ -48,7 +48,7 @@ export const processingActivityRoutes = [ }, { path: "snapshots/:snapshotId/processing-activities/:activityId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ activityId }) => loadQuery(relayEnvironment, processingActivityNodeQuery, { processingActivityId: activityId!, diff --git a/apps/console/src/routes/riskRoutes.ts b/apps/console/src/routes/riskRoutes.ts index 2fd93744f..6d33204bb 100644 --- a/apps/console/src/routes/riskRoutes.ts +++ b/apps/console/src/routes/riskRoutes.ts @@ -8,13 +8,13 @@ import { redirect } from "react-router"; import { lazy } from "@probo/react-lazy"; import { LinkCardSkeleton } from "/components/skeletons/LinkCardSkeleton"; import type { RiskGraphNodeQuery } from "/hooks/graph/__generated__/RiskGraphNodeQuery.graphql"; -import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; import type { RiskGraphListQuery } from "/hooks/graph/__generated__/RiskGraphListQuery.graphql"; export const riskRoutes = [ { path: "risks", - fallback: RisksPageSkeleton, + Fallback: RisksPageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, risksQuery, { organizationId: organizationId!, @@ -25,7 +25,7 @@ export const riskRoutes = [ }, { path: "snapshots/:snapshotId/risks", - fallback: RisksPageSkeleton, + Fallback: RisksPageSkeleton, loader: loaderFromQueryLoader(({ organizationId, snapshotId }) => loadQuery(relayEnvironment, risksQuery, { organizationId: organizationId!, @@ -36,7 +36,7 @@ export const riskRoutes = [ }, { path: "risks/:riskId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ riskId }) => loadQuery(relayEnvironment, riskNodeQuery, { riskId: riskId! }), ), @@ -51,35 +51,35 @@ export const riskRoutes = [ }, { path: "overview", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/risks/tabs/RiskOverviewTab.tsx") ), }, { path: "measures", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/risks/tabs/RiskMeasuresTab.tsx") ), }, { path: "documents", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/risks/tabs/RiskDocumentsTab.tsx") ), }, { path: "controls", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/risks/tabs/RiskControlsTab.tsx") ), }, { path: "obligations", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/risks/tabs/RiskObligationsTab.tsx") ), @@ -88,7 +88,7 @@ export const riskRoutes = [ }, { path: "snapshots/:snapshotId/risks/:riskId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ riskId }) => loadQuery(relayEnvironment, riskNodeQuery, { riskId: riskId! }), ), @@ -103,7 +103,7 @@ export const riskRoutes = [ }, { path: "overview", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/risks/tabs/RiskOverviewTab.tsx") ), diff --git a/apps/console/src/routes/snapshotsRoutes.ts b/apps/console/src/routes/snapshotsRoutes.ts index 8303749f1..8eada48ac 100644 --- a/apps/console/src/routes/snapshotsRoutes.ts +++ b/apps/console/src/routes/snapshotsRoutes.ts @@ -5,12 +5,12 @@ import { snapshotsQuery, snapshotNodeQuery } from "/hooks/graph/SnapshotGraph"; import { lazy } from "@probo/react-lazy"; import type { SnapshotGraphListQuery } from "/hooks/graph/__generated__/SnapshotGraphListQuery.graphql"; import type { SnapshotGraphNodeQuery } from "/hooks/graph/__generated__/SnapshotGraphNodeQuery.graphql"; -import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; export const snapshotsRoutes = [ { path: "snapshots", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, snapshotsQuery, { organizationId }), ), @@ -20,7 +20,7 @@ export const snapshotsRoutes = [ }, { path: "snapshots/:snapshotId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ snapshotId }) => loadQuery(relayEnvironment, snapshotNodeQuery, { snapshotId }), ), diff --git a/apps/console/src/routes/taskRoutes.ts b/apps/console/src/routes/taskRoutes.ts index e3b75c15d..b31f52bc3 100644 --- a/apps/console/src/routes/taskRoutes.ts +++ b/apps/console/src/routes/taskRoutes.ts @@ -3,12 +3,12 @@ import { PageSkeleton } from "/components/skeletons/PageSkeleton"; import { loadQuery } from "react-relay"; import { relayEnvironment } from "/providers/RelayProviders"; import { tasksQuery } from "/hooks/graph/TaskGraph"; -import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; import type { TaskGraphQuery } from "/hooks/graph/__generated__/TaskGraphQuery.graphql"; export const taskRoutes = [ { path: "tasks", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, tasksQuery, { organizationId, diff --git a/apps/console/src/routes/trustCenterRoutes.ts b/apps/console/src/routes/trustCenterRoutes.ts index a47dc1d56..f86a542b2 100644 --- a/apps/console/src/routes/trustCenterRoutes.ts +++ b/apps/console/src/routes/trustCenterRoutes.ts @@ -5,12 +5,12 @@ import { LinkCardSkeleton } from "/components/skeletons/LinkCardSkeleton"; import { lazy } from "@probo/react-lazy"; import { trustCenterQuery } from "../hooks/graph/TrustCenterGraph"; import type { TrustCenterGraphQuery } from "/hooks/graph/__generated__/TrustCenterGraphQuery.graphql"; -import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; export const trustCenterRoutes = [ { path: "trust-center", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, trustCenterQuery, { organizationId }, { fetchPolicy: "network-only" }), ), @@ -20,49 +20,49 @@ export const trustCenterRoutes = [ children: [ { index: true, - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/trustCenter/TrustCenterOverviewTab") ), }, { path: "trust-by", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/trustCenter/TrustCenterReferencesTab") ), }, { path: "audits", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/trustCenter/TrustCenterAuditsTab") ), }, { path: "documents", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/trustCenter/TrustCenterDocumentsTab") ), }, { path: "files", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/trustCenter/TrustCenterFilesTab") ), }, { path: "vendors", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/trustCenter/TrustCenterVendorsTab") ), }, { path: "access", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("/pages/organizations/trustCenter/TrustCenterAccessTab") ), diff --git a/apps/console/src/routes/vendorRoutes.ts b/apps/console/src/routes/vendorRoutes.ts index 7c7ec7095..fecf91bb4 100644 --- a/apps/console/src/routes/vendorRoutes.ts +++ b/apps/console/src/routes/vendorRoutes.ts @@ -4,14 +4,14 @@ import { relayEnvironment } from "/providers/RelayProviders"; import { PageSkeleton } from "/components/skeletons/PageSkeleton"; import { vendorNodeQuery, vendorsQuery } from "/hooks/graph/VendorGraph"; import { LinkCardSkeleton } from "/components/skeletons/LinkCardSkeleton"; -import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "/routes"; +import { loaderFromQueryLoader, withQueryRef, type AppRoute } from "@probo/routes"; import type { VendorGraphListQuery } from "/hooks/graph/__generated__/VendorGraphListQuery.graphql"; import type { VendorGraphNodeQuery } from "/hooks/graph/__generated__/VendorGraphNodeQuery.graphql"; export const vendorRoutes = [ { path: "vendors", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId }) => loadQuery(relayEnvironment, vendorsQuery, { organizationId: organizationId!, @@ -22,7 +22,7 @@ export const vendorRoutes = [ }, { path: "snapshots/:snapshotId/vendors", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ organizationId, snapshotId }) => loadQuery(relayEnvironment, vendorsQuery, { organizationId: organizationId!, @@ -33,7 +33,7 @@ export const vendorRoutes = [ }, { path: "vendors/:vendorId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ vendorId }) => loadQuery(relayEnvironment, vendorNodeQuery, { vendorId: vendorId!, @@ -45,14 +45,14 @@ export const vendorRoutes = [ children: [ { path: "overview", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("../pages/organizations/vendors/tabs/VendorOverviewTab") ), }, { path: "certifications", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import( @@ -62,7 +62,7 @@ export const vendorRoutes = [ }, { path: "compliance", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("../pages/organizations/vendors/tabs/VendorComplianceTab") @@ -70,7 +70,7 @@ export const vendorRoutes = [ }, { path: "risks", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import( @@ -80,7 +80,7 @@ export const vendorRoutes = [ }, { path: "contacts", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("../pages/organizations/vendors/tabs/VendorContactsTab") @@ -88,7 +88,7 @@ export const vendorRoutes = [ }, { path: "services", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("../pages/organizations/vendors/tabs/VendorServicesTab") @@ -98,7 +98,7 @@ export const vendorRoutes = [ }, { path: "snapshots/:snapshotId/vendors/:vendorId", - fallback: PageSkeleton, + Fallback: PageSkeleton, loader: loaderFromQueryLoader(({ vendorId }) => loadQuery(relayEnvironment, vendorNodeQuery, { vendorId: vendorId!, @@ -110,14 +110,14 @@ export const vendorRoutes = [ children: [ { path: "overview", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("../pages/organizations/vendors/tabs/VendorOverviewTab") ), }, { path: "certifications", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import( @@ -127,7 +127,7 @@ export const vendorRoutes = [ }, { path: "compliance", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("../pages/organizations/vendors/tabs/VendorComplianceTab") @@ -135,7 +135,7 @@ export const vendorRoutes = [ }, { path: "risks", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import( @@ -145,7 +145,7 @@ export const vendorRoutes = [ }, { path: "contacts", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("../pages/organizations/vendors/tabs/VendorContactsTab") @@ -153,7 +153,7 @@ export const vendorRoutes = [ }, { path: "services", - fallback: LinkCardSkeleton, + Fallback: LinkCardSkeleton, Component: lazy( () => import("../pages/organizations/vendors/tabs/VendorServicesTab") diff --git a/package-lock.json b/package-lock.json index da5c2f59e..675a2f99b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -97,7 +97,6 @@ "babel-plugin-relay": "^19.0.0", "eslint": "^9.25.0", "eslint-plugin-react-hooks": "^5.2.0", - "eslint-plugin-react-refresh": "^0.4.19", "globals": "^16.0.0", "graphql": "^16.11.0", "prettier": "^3.5.3", @@ -1997,6 +1996,10 @@ "resolved": "packages/react-lazy", "link": true }, + "node_modules/@probo/routes": { + "resolved": "packages/routes", + "link": true + }, "node_modules/@probo/trust": { "resolved": "apps/trust", "link": true @@ -12399,9 +12402,9 @@ "license": "MIT" }, "node_modules/react": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", - "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "version": "19.2.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz", + "integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -12821,9 +12824,9 @@ } }, "node_modules/react-router": { - "version": "7.9.6", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.6.tgz", - "integrity": "sha512-Y1tUp8clYRXpfPITyuifmSoE2vncSME18uVLgaqyxh9H35JWpIfzHo+9y3Fzh5odk/jxPW29IgLgzcdwxGqyNA==", + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.10.0.tgz", + "integrity": "sha512-FVyCOH4IZ0eDDRycODfUqoN8ZSR2LbTvtx6RPsBgzvJ8xAXlMZNCrOFpu+jb8QbtZnpAd/cEki2pwE848pNGxw==", "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -16124,6 +16127,23 @@ "react": ">18.0.0" } }, + "packages/routes": { + "name": "@probo/routes", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@probo/prettier": "1.0.0", + "prettier": "^3.5.3", + "typescript": "^5.8.3", + "vitest": "^3.1.3" + }, + "peerDependencies": { + "react": "^19.2.1", + "react-relay": "^19.0.0", + "react-router": "^7.10.0", + "relay-runtime": "^19.0.0" + } + }, "packages/tsconfig": { "name": "@probo/tsconfig", "version": "0.0.1", diff --git a/packages/helpers/src/routes.tsx b/packages/helpers/src/routes.tsx new file mode 100644 index 000000000..29ad91e38 --- /dev/null +++ b/packages/helpers/src/routes.tsx @@ -0,0 +1,40 @@ +import { ComponentType, LazyExoticComponent } from "react"; +import { EnvironmentProviderOptions, PreloadedQuery } from "react-relay"; +import { LoaderFunction, LoaderFunctionArgs, RouteObject, useLoaderData } from "react-router"; +import { OperationType } from "relay-runtime"; +import { useCleanup } from "./useDelayedEffect"; + +export function withQueryRef< + TQuery extends OperationType, + TEnvironmentProviderOptions = EnvironmentProviderOptions +>( + Component: LazyExoticComponent }>>, +) { + return () => { + const { queryRef, dispose } = useLoaderData(); + + useCleanup(dispose, 1000); + + return + } +} + +export function loaderFromQueryLoader< + TQuery extends OperationType, + TEnvironmentProviderOptions = EnvironmentProviderOptions +>( + queryLoader: (params: Record) => PreloadedQuery +): LoaderFunction { + return ({ params }: LoaderFunctionArgs) => { + const query = queryLoader(params as Record); + return { + queryRef: query, + dispose: query.dispose, + }; + } +} + +export type AppRoute = Omit & { + children?: AppRoute[]; + fallback?: ComponentType; +} diff --git a/apps/console/src/hooks/useDelayedEffect.ts b/packages/helpers/src/useDelayedEffect.ts similarity index 100% rename from apps/console/src/hooks/useDelayedEffect.ts rename to packages/helpers/src/useDelayedEffect.ts diff --git a/packages/hooks/src/useCleanup.ts b/packages/hooks/src/useCleanup.ts new file mode 100644 index 000000000..ee421db8a --- /dev/null +++ b/packages/hooks/src/useCleanup.ts @@ -0,0 +1,19 @@ +import { useEffect, useRef } from "react"; + +/** + * Hook to handle cleanup after a delay + * + * Used for disposing the graphQL query when the component unmounts + */ +export function useCleanup(callback: () => void, delay: number) { + const timer = useRef>(null); + + useEffect(() => { + if (timer.current) { + clearTimeout(timer.current); + } + return () => { + timer.current = setTimeout(callback, delay); + }; + }, [callback, delay]); +} diff --git a/packages/routes/package.json b/packages/routes/package.json new file mode 100644 index 000000000..59ff1faf2 --- /dev/null +++ b/packages/routes/package.json @@ -0,0 +1,27 @@ +{ + "name": "@probo/routes", + "version": "1.0.0", + "description": "", + "main": "./src/index.ts", + "scripts": { + "test": "vitest run", + "test:watch": "vitest", + "format": "prettier --write ./src" + }, + "prettier": "@probo/prettier", + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@probo/prettier": "1.0.0", + "prettier": "^3.5.3", + "typescript": "^5.8.3", + "vitest": "^3.1.3" + }, + "peerDependencies": { + "react": "^19.2.1", + "react-relay": "^19.0.0", + "react-router": "^7.10.0", + "relay-runtime": "^19.0.0" + } +} diff --git a/packages/routes/src/appRoute.tsx b/packages/routes/src/appRoute.tsx new file mode 100644 index 000000000..06461abe4 --- /dev/null +++ b/packages/routes/src/appRoute.tsx @@ -0,0 +1,30 @@ +import { ComponentType, Suspense } from "react"; +import { RouteObject } from "react-router"; + +export type AppRoute = Omit & { + children?: AppRoute[]; + Fallback?: ComponentType; +} + +export function routeFromAppRoute(appRoute: AppRoute): RouteObject { + const { Component, Fallback, children, ...rest } = appRoute; + let route = { ...rest } as RouteObject; + + if (Component && Fallback) { + const OriginalComponent = Component as ComponentType; + + route = { + ...route, + Component: () => ( + }> + + + ), + }; + } + + return { + ...route, + children: children?.map(routeFromAppRoute), + } as RouteObject; +} diff --git a/packages/routes/src/index.ts b/packages/routes/src/index.ts new file mode 100644 index 000000000..b6d3ae55a --- /dev/null +++ b/packages/routes/src/index.ts @@ -0,0 +1,2 @@ +export { routeFromAppRoute, type AppRoute } from "./appRoute"; +export { withQueryRef, loaderFromQueryLoader } from "./relay"; diff --git a/packages/routes/src/relay.tsx b/packages/routes/src/relay.tsx new file mode 100644 index 000000000..e71cd6171 --- /dev/null +++ b/packages/routes/src/relay.tsx @@ -0,0 +1,35 @@ +import { ComponentType } from "react"; +import { EnvironmentProviderOptions, PreloadedQuery } from "react-relay"; +import { LoaderFunction, LoaderFunctionArgs, useLoaderData } from "react-router"; +import { OperationType } from "relay-runtime"; +import { useCleanup } from "@probo/hooks"; + +export function withQueryRef< + TQuery extends OperationType, + TEnvironmentProviderOptions = EnvironmentProviderOptions +>( + Component: ComponentType<{ queryRef: PreloadedQuery }>, +) { + return () => { + const { queryRef, dispose } = useLoaderData(); + + useCleanup(dispose, 1000); + + return + } +} + +export function loaderFromQueryLoader< + TQuery extends OperationType, + TEnvironmentProviderOptions = EnvironmentProviderOptions +>( + queryLoader: (params: Record) => PreloadedQuery +): LoaderFunction { + return ({ params }: LoaderFunctionArgs) => { + const query = queryLoader(params as Record); + return { + queryRef: query, + dispose: query.dispose, + }; + } +} diff --git a/packages/routes/tsconfig.json b/packages/routes/tsconfig.json new file mode 100644 index 000000000..e72dedb4d --- /dev/null +++ b/packages/routes/tsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "lib": ["ES2021", "dom"], + "jsx": "react-jsx", + } +}