From ffb2c2c5d9e9594ea0ff668da8c5e0f2c1cb3d3f Mon Sep 17 00:00:00 2001 From: Z8MB1E Date: Mon, 7 Sep 2026 05:07:43 -0400 Subject: [PATCH] feat(missions): show op host on side op cards and mission pages Side ops now credit their creator: mission cards get a 'Hosted by X' meta entry and the mission detail page gets a Host chip. Display name preferred over username; only shown for side ops with a populated createdBy. --- .../intelligence/missions/[id]/page.tsx | 21 ++++++++++++++++++- .../frontend/intelligence/MissionCard.tsx | 20 +++++++++++++++--- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/app/(frontend)/intelligence/missions/[id]/page.tsx b/src/app/(frontend)/intelligence/missions/[id]/page.tsx index c5b108c..c4e42be 100644 --- a/src/app/(frontend)/intelligence/missions/[id]/page.tsx +++ b/src/app/(frontend)/intelligence/missions/[id]/page.tsx @@ -3,7 +3,7 @@ import { getPayload } from "payload"; import { notFound } from "next/navigation"; import Link from "next/link"; import { headers as nextHeaders } from "next/headers"; -import type { Campaign, Map, Media, Mission } from "@/payload-types"; +import type { Campaign, Map, Media, Mission, User } from "@/payload-types"; import { ArrowLeftIcon, CalendarDaysIcon, @@ -13,6 +13,7 @@ import { FlagIcon, MapPinIcon, ServerIcon, + UserIcon, } from "lucide-react"; import { Item, ItemContent, ItemHeader, ItemTitle } from "@/components/ui/item"; import { ClientDate } from "@/components/frontend/ClientDate"; @@ -94,6 +95,13 @@ export default async function MissionDetailPage({ params }: MissionDetailPagePro ? (missionWithCoverImage.coverImage as Media) : null; const coverImageUrl = coverImage?.url ?? null; + const host = + mission.operationType === "side" && + typeof mission.createdBy === "object" && + mission.createdBy !== null + ? (mission.createdBy as User) + : null; + const hostLabel = host ? (host.displayName || host.username) : null; const durationHours = Math.floor(mission.classification.estimatedDuration / 60); const durationMins = mission.classification.estimatedDuration % 60; @@ -328,6 +336,17 @@ export default async function MissionDetailPage({ params }: MissionDetailPagePro )} + {hostLabel && ( +
+ + + + Host + + {hostLabel} + +
+ )} {campaign && ( - + {mission.codeName} {mission.name} @@ -131,7 +139,7 @@ export function MissionCard({ - {operationTypeLabels[mission.operationType] ?? mission.operationType} + {operationTypeLabels[mission.operationType] ?? mission.operationType} Operation )} + {showHost && ( + + + Hosted by {hostLabel} + + )} {campaign && {campaign.name}}