Rewrite context routes to use useQueryLoader pattern
Replace loaderFromQueryLoader/loadQuery in route definitions with useQueryLoader inside dedicated Loader components, matching the compliance-page pattern. Use index routes instead of redirect hacks. Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
@@ -5,7 +5,7 @@ import { Outlet } from "react-router";
|
|||||||
|
|
||||||
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||||
|
|
||||||
export default function ContextLayout() {
|
export default function ContextLayoutLoader() {
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
const organizationId = useOrganizationId();
|
const organizationId = useOrganizationId();
|
||||||
const prefix = `/organizations/${organizationId}/context`;
|
const prefix = `/organizations/${organizationId}/context`;
|
||||||
@@ -21,7 +21,7 @@ export default function ContextLayout() {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<TabLink to={`${prefix}/overview`}>{__("Context")}</TabLink>
|
<TabLink to={prefix} end>{__("Context")}</TabLink>
|
||||||
<TabLink to={`${prefix}/meetings`}>{__("Meetings")}</TabLink>
|
<TabLink to={`${prefix}/meetings`}>{__("Meetings")}</TabLink>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
<Outlet />
|
<Outlet />
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
import { type PreloadedQuery, usePreloadedQuery } from "react-relay";
|
import { useEffect } from "react";
|
||||||
|
import { type PreloadedQuery, usePreloadedQuery, useQueryLoader } from "react-relay";
|
||||||
import { graphql } from "relay-runtime";
|
import { graphql } from "relay-runtime";
|
||||||
|
|
||||||
import type { ContextPageLoaderQuery } from "#/__generated__/core/ContextPageLoaderQuery.graphql";
|
import type { ContextPageLoaderQuery } from "#/__generated__/core/ContextPageLoaderQuery.graphql";
|
||||||
|
import { LinkCardSkeleton } from "#/components/skeletons/LinkCardSkeleton";
|
||||||
|
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||||
|
import { CoreRelayProvider } from "#/providers/CoreRelayProvider";
|
||||||
|
|
||||||
import ContextPage from "./ContextPage";
|
import ContextPage from "./ContextPage";
|
||||||
|
|
||||||
export const contextPageQuery = graphql`
|
const contextPageQuery = graphql`
|
||||||
query ContextPageLoaderQuery($organizationId: ID!) {
|
query ContextPageLoaderQuery($organizationId: ID!) {
|
||||||
organization: node(id: $organizationId) {
|
organization: node(id: $organizationId) {
|
||||||
... on Organization {
|
... on Organization {
|
||||||
@@ -15,12 +19,31 @@ export const contextPageQuery = graphql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type Props = {
|
function ContextPageQueryLoader() {
|
||||||
queryRef: PreloadedQuery<ContextPageLoaderQuery>;
|
const organizationId = useOrganizationId();
|
||||||
};
|
const [queryRef, loadQuery] = useQueryLoader<ContextPageLoaderQuery>(contextPageQuery);
|
||||||
|
|
||||||
export default function ContextPageLoader(props: Props) {
|
useEffect(() => {
|
||||||
const data = usePreloadedQuery(contextPageQuery, props.queryRef);
|
if (!queryRef) {
|
||||||
|
loadQuery({ organizationId });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!queryRef) return <LinkCardSkeleton />;
|
||||||
|
|
||||||
|
return <ContextPageInner queryRef={queryRef} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ContextPageInner({ queryRef }: { queryRef: PreloadedQuery<ContextPageLoaderQuery> }) {
|
||||||
|
const data = usePreloadedQuery(contextPageQuery, queryRef);
|
||||||
|
|
||||||
return <ContextPage organization={data.organization} />;
|
return <ContextPage organization={data.organization} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function ContextPageLoader() {
|
||||||
|
return (
|
||||||
|
<CoreRelayProvider>
|
||||||
|
<ContextPageQueryLoader />
|
||||||
|
</CoreRelayProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
import { useQueryLoader } from "react-relay";
|
||||||
|
import { useParams } from "react-router";
|
||||||
|
|
||||||
|
import type { MeetingDetailPageQuery } from "#/__generated__/core/MeetingDetailPageQuery.graphql";
|
||||||
|
import { PageSkeleton } from "#/components/skeletons/PageSkeleton";
|
||||||
|
import { CoreRelayProvider } from "#/providers/CoreRelayProvider";
|
||||||
|
|
||||||
|
import MeetingDetailPage, { meetingDetailPageQuery } from "./MeetingDetailPage";
|
||||||
|
|
||||||
|
function MeetingDetailPageQueryLoader() {
|
||||||
|
const { meetingId } = useParams<{ meetingId: string }>();
|
||||||
|
const [queryRef, loadQuery] = useQueryLoader<MeetingDetailPageQuery>(meetingDetailPageQuery);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!queryRef && meetingId) {
|
||||||
|
loadQuery({ meetingId });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!queryRef) return <PageSkeleton />;
|
||||||
|
|
||||||
|
return <MeetingDetailPage queryRef={queryRef} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function MeetingDetailPageLoader() {
|
||||||
|
return (
|
||||||
|
<CoreRelayProvider>
|
||||||
|
<MeetingDetailPageQueryLoader />
|
||||||
|
</CoreRelayProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
import { useQueryLoader } from "react-relay";
|
||||||
|
|
||||||
|
import type { MeetingsPageQuery } from "#/__generated__/core/MeetingsPageQuery.graphql";
|
||||||
|
import { LinkCardSkeleton } from "#/components/skeletons/LinkCardSkeleton";
|
||||||
|
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||||
|
import { CoreRelayProvider } from "#/providers/CoreRelayProvider";
|
||||||
|
|
||||||
|
import MeetingsPage, { meetingsPageQuery } from "./MeetingsPage";
|
||||||
|
|
||||||
|
function MeetingsPageQueryLoader() {
|
||||||
|
const organizationId = useOrganizationId();
|
||||||
|
const [queryRef, loadQuery] = useQueryLoader<MeetingsPageQuery>(meetingsPageQuery);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!queryRef) {
|
||||||
|
loadQuery({ organizationId });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!queryRef) return <LinkCardSkeleton />;
|
||||||
|
|
||||||
|
return <MeetingsPage queryRef={queryRef} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function MeetingsPageLoader() {
|
||||||
|
return (
|
||||||
|
<CoreRelayProvider>
|
||||||
|
<MeetingsPageQueryLoader />
|
||||||
|
</CoreRelayProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,113 +1,46 @@
|
|||||||
import { lazy } from "@probo/react-lazy";
|
import { lazy } from "@probo/react-lazy";
|
||||||
import {
|
import type { AppRoute } from "@probo/routes";
|
||||||
type AppRoute,
|
|
||||||
loaderFromQueryLoader,
|
|
||||||
withQueryRef,
|
|
||||||
} from "@probo/routes";
|
|
||||||
import { Fragment } from "react";
|
|
||||||
import { loadQuery } from "react-relay";
|
|
||||||
import { type LoaderFunctionArgs, redirect } from "react-router";
|
|
||||||
|
|
||||||
import type { ContextPageLoaderQuery } from "#/__generated__/core/ContextPageLoaderQuery.graphql";
|
|
||||||
import type { MeetingDetailPageQuery } from "#/__generated__/core/MeetingDetailPageQuery.graphql";
|
|
||||||
import type { MeetingsPageQuery } from "#/__generated__/core/MeetingsPageQuery.graphql";
|
|
||||||
import { LinkCardSkeleton } from "#/components/skeletons/LinkCardSkeleton";
|
import { LinkCardSkeleton } from "#/components/skeletons/LinkCardSkeleton";
|
||||||
import { PageSkeleton } from "#/components/skeletons/PageSkeleton";
|
import { PageSkeleton } from "#/components/skeletons/PageSkeleton";
|
||||||
import { coreEnvironment } from "#/environments";
|
|
||||||
import { contextPageQuery } from "#/pages/organizations/context/ContextPageLoader";
|
|
||||||
import { meetingDetailPageQuery } from "#/pages/organizations/meetings/MeetingDetailPage";
|
|
||||||
import { meetingsPageQuery } from "#/pages/organizations/meetings/MeetingsPage";
|
|
||||||
|
|
||||||
const meetingTabs = (prefix: string) => {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
path: `${prefix}`,
|
|
||||||
loader: ({
|
|
||||||
params: { organizationId, meetingId },
|
|
||||||
}: LoaderFunctionArgs) => {
|
|
||||||
const basePath = `/organizations/${organizationId}/context/meetings/${meetingId}`;
|
|
||||||
const redirectPath = `${basePath}/minutes`;
|
|
||||||
// eslint-disable-next-line
|
|
||||||
throw redirect(redirectPath);
|
|
||||||
},
|
|
||||||
Component: Fragment,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: `${prefix}minutes`,
|
|
||||||
Fallback: LinkCardSkeleton,
|
|
||||||
Component: lazy(
|
|
||||||
() => import("../pages/organizations/meetings/tabs/MeetingMinutesTab"),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const contextRoutes = [
|
export const contextRoutes = [
|
||||||
{
|
{
|
||||||
path: "context",
|
path: "context",
|
||||||
Fallback: PageSkeleton,
|
Fallback: PageSkeleton,
|
||||||
Component: lazy(
|
Component: lazy(
|
||||||
() => import("#/pages/organizations/context/ContextLayout"),
|
() => import("#/pages/organizations/context/ContextLayoutLoader"),
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "",
|
index: true,
|
||||||
loader: ({
|
Fallback: LinkCardSkeleton,
|
||||||
params: { organizationId },
|
Component: lazy(
|
||||||
}: LoaderFunctionArgs) => {
|
() => import("#/pages/organizations/context/ContextPageLoader"),
|
||||||
// eslint-disable-next-line
|
|
||||||
throw redirect(`/organizations/${organizationId}/context/overview`);
|
|
||||||
},
|
|
||||||
Component: Fragment,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "overview",
|
|
||||||
Fallback: PageSkeleton,
|
|
||||||
loader: loaderFromQueryLoader(({ organizationId }) =>
|
|
||||||
loadQuery<ContextPageLoaderQuery>(
|
|
||||||
coreEnvironment,
|
|
||||||
contextPageQuery,
|
|
||||||
{ organizationId },
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Component: withQueryRef(
|
|
||||||
lazy(
|
|
||||||
() => import("#/pages/organizations/context/ContextPageLoader"),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "meetings",
|
path: "meetings",
|
||||||
Fallback: PageSkeleton,
|
Fallback: LinkCardSkeleton,
|
||||||
loader: loaderFromQueryLoader(({ organizationId }) =>
|
Component: lazy(
|
||||||
loadQuery<MeetingsPageQuery>(
|
() => import("#/pages/organizations/meetings/MeetingsPageLoader"),
|
||||||
coreEnvironment,
|
|
||||||
meetingsPageQuery,
|
|
||||||
{ organizationId },
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Component: withQueryRef(
|
|
||||||
lazy(
|
|
||||||
() => import("#/pages/organizations/meetings/MeetingsPage"),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "meetings/:meetingId",
|
path: "meetings/:meetingId",
|
||||||
Fallback: PageSkeleton,
|
Fallback: PageSkeleton,
|
||||||
loader: loaderFromQueryLoader(({ meetingId }) =>
|
Component: lazy(
|
||||||
loadQuery<MeetingDetailPageQuery>(
|
() => import("#/pages/organizations/meetings/MeetingDetailPageLoader"),
|
||||||
coreEnvironment,
|
|
||||||
meetingDetailPageQuery,
|
|
||||||
{ meetingId },
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Component: withQueryRef(
|
children: [
|
||||||
lazy(
|
{
|
||||||
() => import("../pages/organizations/meetings/MeetingDetailPage"),
|
index: true,
|
||||||
),
|
Fallback: LinkCardSkeleton,
|
||||||
),
|
Component: lazy(
|
||||||
children: [...meetingTabs("")],
|
() => import("#/pages/organizations/meetings/tabs/MeetingMinutesTab"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user