- 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
96 lines
3.1 KiB
TypeScript
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>
|
|
);
|
|
}
|