- Add EquipmentEditorDialog for per-category attachments, skins, and custom names - Add Wardrobe component with soldier image and clickable equipment slots - Add WardrobePanel with loadout selector and current equipment display - Add WardrobeSlotPicker dialog for equipping items from locker - Add equip/unequip loadout functionality with equipped badge - Add equipment schema to LockerStorages (attachments, skin, customName) - Add wardrobe slot layout with hotspot positions for each equipment type - Add locker:item-attach, locker:item-detach, locker:item-skin event types - Update LoadoutCard to show equipped status and equipment list - Update LoadoutsPanel to pass ownedItems for equipment display
77 lines
2.3 KiB
TypeScript
77 lines
2.3 KiB
TypeScript
import config from "@payload-config";
|
|
import { getPayload } from "payload";
|
|
import { headers as nextHeaders } from "next/headers";
|
|
import type { Asset, Loadout, LockerStorage } from "@/payload-types";
|
|
import { LockKeyholeIcon } from "lucide-react";
|
|
import { ensureLockerStorage, getLockerGridDimensions } from "@/lib/locker";
|
|
import { LockerView } from "@/components/frontend/locker/LockerView";
|
|
import hasRoles from "@/utils/access-control/hasRoles";
|
|
|
|
export const metadata = {
|
|
title: "Locker — Polaris Task Force",
|
|
};
|
|
|
|
export default async function LockerPage() {
|
|
const payload = await getPayload({ config });
|
|
const { user } = await payload.auth({
|
|
headers: await nextHeaders(),
|
|
canSetHeaders: false,
|
|
});
|
|
|
|
const userId = user?.id as number;
|
|
const locker = await ensureLockerStorage(payload, userId);
|
|
const lockerFull = (await payload.findByID({
|
|
collection: "locker-storages",
|
|
id: locker.id,
|
|
depth: 2,
|
|
overrideAccess: true,
|
|
})) as unknown as LockerStorage;
|
|
|
|
const loadoutsRes = await payload.find({
|
|
collection: "loadouts",
|
|
where: { ownerUser: { equals: userId } },
|
|
sort: "name",
|
|
limit: 100,
|
|
depth: 1,
|
|
});
|
|
const loadouts = loadoutsRes.docs as unknown as Loadout[];
|
|
|
|
const isManager = user ? hasRoles(["admin", "developer"], user) : false;
|
|
|
|
let assetsCatalog: Asset[] = [];
|
|
if (isManager) {
|
|
const assetsRes = await payload.find({
|
|
collection: "assets",
|
|
sort: "name",
|
|
limit: 500,
|
|
depth: 0,
|
|
});
|
|
assetsCatalog = assetsRes.docs as unknown as Asset[];
|
|
}
|
|
|
|
const grid = await getLockerGridDimensions(payload);
|
|
|
|
return (
|
|
<div className="p-5 flex flex-col gap-6">
|
|
<div className="flex flex-col gap-1">
|
|
<div className="flex items-center gap-2">
|
|
<LockKeyholeIcon className="size-5 text-muted-foreground" />
|
|
<h1 className="text-lg font-semibold">Personal Locker</h1>
|
|
</div>
|
|
<p className="text-sm text-muted-foreground">
|
|
Store, organize, and equip your personal gear and loadouts.
|
|
</p>
|
|
</div>
|
|
|
|
<LockerView
|
|
locker={lockerFull}
|
|
gridWidth={grid.width}
|
|
gridHeight={grid.height}
|
|
loadouts={loadouts}
|
|
assetsCatalog={assetsCatalog}
|
|
isManager={isManager}
|
|
userName={user?.username ?? "Member"}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|