- Add hasIntelligenceQualification access helper - Redirect non-qualified users away from /intelligence - Hide mission and campaign widgets on the dashboard for non-qualified users - Guard hasLogisticsQualification against a null user
129 lines
4.4 KiB
TypeScript
129 lines
4.4 KiB
TypeScript
import config from "@payload-config";
|
|
import { getPayload } from "payload";
|
|
import { headers as nextHeaders } from "next/headers";
|
|
import { redirect } from "next/navigation";
|
|
import Link from "next/link";
|
|
import type { Campaign, Mission, Faction } from "@/payload-types";
|
|
import { hasIntelligenceQualification } from "@/utils/access-control/hasIntelligenceQualification";
|
|
import { CrosshairIcon, ArrowRightIcon } from "lucide-react";
|
|
import {
|
|
Item,
|
|
ItemContent,
|
|
ItemDescription,
|
|
ItemHeader,
|
|
ItemTitle,
|
|
} from "@/components/ui/item";
|
|
import { CampaignCard } from "@/components/frontend/intelligence/CampaignCard";
|
|
|
|
export const metadata = {
|
|
title: "Intelligence — Polaris Task Force",
|
|
};
|
|
|
|
export default async function IntelligenceOverviewPage() {
|
|
const payload = await getPayload({ config });
|
|
const headers = await nextHeaders();
|
|
const { user } = await payload.auth({ headers, canSetHeaders: false });
|
|
|
|
if (!user || !(await hasIntelligenceQualification(payload, user))) {
|
|
redirect("/");
|
|
}
|
|
|
|
const [campaignsRes, factionsRes] = await Promise.all([
|
|
payload
|
|
.find({
|
|
collection: "campaigns",
|
|
where: { status: { equals: "inProgress" } },
|
|
limit: 10,
|
|
sort: "-createdAt",
|
|
})
|
|
.catch(() => ({ docs: [] })),
|
|
payload.find({
|
|
collection: "factions",
|
|
limit: 100,
|
|
select: { name: true, type: true },
|
|
}),
|
|
]);
|
|
|
|
const campaigns = campaignsRes.docs as Campaign[];
|
|
const factions = factionsRes.docs as Faction[];
|
|
|
|
return (
|
|
<div className="p-5 flex flex-col gap-6">
|
|
<div className="flex flex-col gap-1">
|
|
<div className="flex items-center gap-2">
|
|
<CrosshairIcon className="size-5 text-muted-foreground" />
|
|
<h1 className="text-lg font-semibold">Intelligence</h1>
|
|
</div>
|
|
<p className="text-sm text-muted-foreground">
|
|
Campaigns, missions, and faction intelligence for the theater of
|
|
operations.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-3">
|
|
<Link href="/intelligence/campaigns">
|
|
<Item
|
|
variant="outline"
|
|
className="cursor-pointer group transition-all duration-200 hover:scale-[1.01]"
|
|
>
|
|
<ItemHeader>
|
|
<ItemTitle>Campaigns</ItemTitle>
|
|
<ArrowRightIcon className="size-4 text-muted-foreground group-hover:text-primary transition-colors" />
|
|
</ItemHeader>
|
|
<ItemContent>
|
|
<ItemDescription>
|
|
Active and completed campaigns across all theaters.
|
|
</ItemDescription>
|
|
</ItemContent>
|
|
</Item>
|
|
</Link>
|
|
<Link href="/intelligence/missions">
|
|
<Item
|
|
variant="outline"
|
|
className="cursor-pointer group transition-all duration-200 hover:scale-[1.01]"
|
|
>
|
|
<ItemHeader>
|
|
<ItemTitle>Missions</ItemTitle>
|
|
<ArrowRightIcon className="size-4 text-muted-foreground group-hover:text-primary transition-colors" />
|
|
</ItemHeader>
|
|
<ItemContent>
|
|
<ItemDescription>
|
|
Operation briefings, objectives, and schedules.
|
|
</ItemDescription>
|
|
</ItemContent>
|
|
</Item>
|
|
</Link>
|
|
<Link href="/intelligence/factions">
|
|
<Item
|
|
variant="outline"
|
|
className="cursor-pointer group transition-all duration-200 hover:scale-[1.01]"
|
|
>
|
|
<ItemHeader>
|
|
<ItemTitle>Factions</ItemTitle>
|
|
<ArrowRightIcon className="size-4 text-muted-foreground group-hover:text-primary transition-colors" />
|
|
</ItemHeader>
|
|
<ItemContent>
|
|
<ItemDescription>
|
|
{factions.length} faction{factions.length !== 1 ? "s" : ""}{" "}
|
|
tracked in the AO.
|
|
</ItemDescription>
|
|
</ItemContent>
|
|
</Item>
|
|
</Link>
|
|
</div>
|
|
|
|
{campaigns.length > 0 && (
|
|
<section className="flex flex-col gap-3">
|
|
<h2 className="text-sm font-semibold uppercase tracking-wider text-muted-foreground">
|
|
Active Campaigns
|
|
</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
|
|
{campaigns.map((campaign) => (
|
|
<CampaignCard key={campaign.id} campaign={campaign} />
|
|
))}
|
|
</div>
|
|
</section>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|