1
0
Fork 0
polaris-task-force/src/components/frontend/dashboard/ProfileSummary.tsx
Z8MB1E 25c088aebf feat: add operations dashboard with mission briefing and stats
- Redesign homepage as authenticated operations dashboard
- Add ProfileSummary, MissionBriefing, RecentEvents, QuickStats components
- Add UpcomingMissions and ActiveCampaigns sidebar widgets
- Redirect /dashboard to / (homepage is now the dashboard)
- Show welcome screen with login link for unauthenticated users
2026-07-31 20:01:50 -04:00

96 lines
3.1 KiB
TypeScript

import Link from "next/link";
import type { Rank, Media, Assignment } from "@/payload-types";
import type { ResolvedLevel } from "@/utils/xp/resolveLevel";
import {
Item,
ItemContent,
ItemDescription,
ItemHeader,
ItemTitle,
} from "@/components/ui/item";
import { BadgeCheckIcon, ShieldIcon, SparkleIcon, UserIcon } from "lucide-react";
interface ProfileSummaryProps {
displayName: string;
username: string;
rank: Pick<Rank, "name" | "abbreviation"> & { insigniaUrl?: string | null };
xpLevel: ResolvedLevel;
assignments: Pick<Assignment, "name" | "type" | "callsign">[];
}
export function ProfileSummary({
displayName,
username,
rank,
xpLevel,
assignments,
}: ProfileSummaryProps) {
return (
<Item variant="outline">
<ItemHeader>
<div className="flex items-center gap-2">
<UserIcon className="size-4 text-muted-foreground" />
<ItemTitle>Service Summary</ItemTitle>
</div>
<Link
href={`/profile/${username}`}
className="text-xs text-muted-foreground hover:text-primary transition-colors"
>
View full record
</Link>
</ItemHeader>
<ItemContent className="flex flex-col gap-4">
<div className="flex items-start gap-4">
{rank.insigniaUrl && (
<img
src={rank.insigniaUrl}
alt={rank.name}
className="size-14 object-contain shrink-0"
/>
)}
<div className="flex flex-col gap-1 min-w-0">
<h3 className="text-lg font-bold tracking-tight uppercase">
{displayName}
</h3>
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<span className="font-medium text-foreground">{rank.name}</span>
<span className="text-border">|</span>
<span className="uppercase tracking-wide text-xs font-semibold text-primary">
{xpLevel.levelName}
</span>
</div>
</div>
</div>
<div className="flex items-center gap-2">
<div className="flex-1 h-2 bg-border rounded-full overflow-hidden max-w-xs">
<div
className="h-full bg-primary rounded-full transition-all"
style={{ width: `${Math.min(xpLevel.progress, 100)}%` }}
/>
</div>
<span className="text-xs font-mono text-muted-foreground">
{xpLevel.xp.toLocaleString()} XP
</span>
</div>
{assignments.length > 0 && (
<div className="flex flex-wrap gap-2">
{assignments.map((a) => (
<span
key={a.name}
className="text-xs font-mono bg-muted border border-border px-2.5 py-1 rounded-md"
>
{a.callsign ? `[${a.callsign}] ` : ""}
{a.name}
<span className="text-muted-foreground ml-1.5">
({a.type})
</span>
</span>
))}
</div>
)}
</ItemContent>
</Item>
);
}