src/lib/auth/page.tsx
Linked repository file from this build.
import { NavigationLink as Link } from "@/components/navigation-link";
import { redirect } from "next/navigation";
import type { ReactNode } from "react";
import { AccountSetupError, getActor } from "./server";
import { AccessError, can, type Capability } from "./scope";
import { ReviewProvider } from "@/features/reviews/provider";
const capabilityLabels: Partial<Record<Capability, string>> = {
import: "imports",
report: "reports",
export: "exports",
approvalQueue: "the Approval Queue",
};
/** Server wrapper for app pages: requires a session and, if given, one capability. */
export async function ProtectedPage({
children,
capability,
}: {
children: ReactNode;
capability?: Capability;
}) {
const actor = await getPageActor();
const content =
capability && !can(actor, capability) ? (
<main className="mx-auto max-w-xl space-y-4 p-8">
<h1 className="text-xl font-semibold">Access restricted</h1>
<p>Your role does not include {capabilityLabels[capability] ?? capability}.</p>
<Link className="underline" href="/dashboard">
Return to Home
</Link>
</main>
) : (
children
);
return <ReviewProvider loadReview={false}>{content}</ReviewProvider>;
}
export async function getPageActor() {
let actor;
try {
actor = await getActor();
} catch (error) {
if (error instanceof AccountSetupError) redirect("/account-setup");
if (error instanceof AccessError && error.status === 401) redirect("/sign-in");
throw error;
}
return actor;
}