feat(intelligence): gate intelligence content behind the intelligence qualification
- 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
This commit is contained in:
parent
c81036bd82
commit
caae76e6b2
4 changed files with 49 additions and 3 deletions
|
|
@ -1,7 +1,10 @@
|
||||||
import config from "@payload-config";
|
import config from "@payload-config";
|
||||||
import { getPayload } from "payload";
|
import { getPayload } from "payload";
|
||||||
|
import { headers as nextHeaders } from "next/headers";
|
||||||
|
import { redirect } from "next/navigation";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import type { Campaign, Mission, Faction } from "@/payload-types";
|
import type { Campaign, Mission, Faction } from "@/payload-types";
|
||||||
|
import { hasIntelligenceQualification } from "@/utils/access-control/hasIntelligenceQualification";
|
||||||
import { CrosshairIcon, ArrowRightIcon } from "lucide-react";
|
import { CrosshairIcon, ArrowRightIcon } from "lucide-react";
|
||||||
import {
|
import {
|
||||||
Item,
|
Item,
|
||||||
|
|
@ -18,6 +21,12 @@ export const metadata = {
|
||||||
|
|
||||||
export default async function IntelligenceOverviewPage() {
|
export default async function IntelligenceOverviewPage() {
|
||||||
const payload = await getPayload({ config });
|
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([
|
const [campaignsRes, factionsRes] = await Promise.all([
|
||||||
payload
|
payload
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { getPayload } from "payload";
|
||||||
import { headers as nextHeaders } from "next/headers";
|
import { headers as nextHeaders } from "next/headers";
|
||||||
import type { User, Rank, Media, Assignment, Campaign, Map, GameStructure } from "@/payload-types";
|
import type { User, Rank, Media, Assignment, Campaign, Map, GameStructure } from "@/payload-types";
|
||||||
import { resolveLevel } from "@/utils/xp/resolveLevel";
|
import { resolveLevel } from "@/utils/xp/resolveLevel";
|
||||||
|
import { hasIntelligenceQualification } from "@/utils/access-control/hasIntelligenceQualification";
|
||||||
import { ProfileSummary } from "@/components/frontend/dashboard/ProfileSummary";
|
import { ProfileSummary } from "@/components/frontend/dashboard/ProfileSummary";
|
||||||
import { MissionBriefing } from "@/components/frontend/dashboard/MissionBriefing";
|
import { MissionBriefing } from "@/components/frontend/dashboard/MissionBriefing";
|
||||||
import { RecentEvents } from "@/components/frontend/dashboard/RecentEvents";
|
import { RecentEvents } from "@/components/frontend/dashboard/RecentEvents";
|
||||||
|
|
@ -19,6 +20,8 @@ export default async function HomePage() {
|
||||||
|
|
||||||
const userId = user.id;
|
const userId = user.id;
|
||||||
|
|
||||||
|
const hasIntelligence = await hasIntelligenceQualification(payload, user).catch(() => false);
|
||||||
|
|
||||||
const [profileRes, experienceRes, assignmentRes] = await Promise.all([
|
const [profileRes, experienceRes, assignmentRes] = await Promise.all([
|
||||||
payload.find({
|
payload.find({
|
||||||
collection: "profiles",
|
collection: "profiles",
|
||||||
|
|
@ -229,8 +232,8 @@ export default async function HomePage() {
|
||||||
|
|
||||||
{/* ── Right Sidebar (1/3) ─────────────────────────── */}
|
{/* ── Right Sidebar (1/3) ─────────────────────────── */}
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<UpcomingMissions missions={upcomingMissions} />
|
{hasIntelligence && <UpcomingMissions missions={upcomingMissions} />}
|
||||||
<ActiveCampaigns campaigns={activeCampaigns} />
|
{hasIntelligence && <ActiveCampaigns campaigns={activeCampaigns} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
32
src/utils/access-control/hasIntelligenceQualification.ts
Normal file
32
src/utils/access-control/hasIntelligenceQualification.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import type { Payload } from "payload";
|
||||||
|
|
||||||
|
export async function hasIntelligenceQualification(
|
||||||
|
payload: Payload,
|
||||||
|
user: { id: number | string; roles?: unknown } | null | undefined,
|
||||||
|
): Promise<boolean> {
|
||||||
|
if (!user) return false;
|
||||||
|
|
||||||
|
const roles = user.roles as string[] | undefined;
|
||||||
|
if (roles?.includes("developer") || roles?.includes("admin")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const profile = (await payload.find({
|
||||||
|
collection: "profiles",
|
||||||
|
where: { user: { equals: user.id as number } },
|
||||||
|
depth: 4,
|
||||||
|
limit: 1,
|
||||||
|
})) as unknown as { docs: Array<any> };
|
||||||
|
|
||||||
|
const userProfile = profile.docs[0];
|
||||||
|
|
||||||
|
if (!userProfile || !userProfile.progression || !userProfile.progression.qualifications) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return userProfile.progression.qualifications.some((qualification: any) => {
|
||||||
|
return typeof qualification === "string"
|
||||||
|
? qualification.toLowerCase() === "intelligence"
|
||||||
|
: qualification?.name?.toLowerCase() === "intelligence";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,8 @@ export async function hasLogisticsQualification(
|
||||||
payload: Payload,
|
payload: Payload,
|
||||||
user: { id: number | string; roles?: unknown } | null | undefined,
|
user: { id: number | string; roles?: unknown } | null | undefined,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
|
if (!user) return false;
|
||||||
|
|
||||||
const roles = user.roles as string[] | undefined;
|
const roles = user.roles as string[] | undefined;
|
||||||
if (roles?.includes("developer") || roles?.includes("admin")) {
|
if (roles?.includes("developer") || roles?.includes("admin")) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -16,7 +18,7 @@ export async function hasLogisticsQualification(
|
||||||
|
|
||||||
const profileRes = await payload.find({
|
const profileRes = await payload.find({
|
||||||
collection: "profiles",
|
collection: "profiles",
|
||||||
where: { user: { equals: user.id } },
|
where: { user: { equals: user.id as number } },
|
||||||
limit: 1,
|
limit: 1,
|
||||||
depth: 1,
|
depth: 1,
|
||||||
select: {
|
select: {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue