Wrap next/link in a shared Link component that ships prefetch=false by default, so no route is ever prefetched (viewport or hover) anymore, and drop the DNS prefetch hint. Removes hidden background requests that were the source of intermittent issues.
140 lines
3.8 KiB
TypeScript
140 lines
3.8 KiB
TypeScript
import { asc, eq } from "drizzle-orm";
|
|
import { ChevronRight } from "lucide-react";
|
|
import { notFound, redirect } from "next/navigation";
|
|
import { Fragment } from "react";
|
|
import Link from "@/components/link";
|
|
import { CatalogPages, db } from "@/lib/db";
|
|
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
|
import { loadCatalogItemsData } from "@/lib/services/catalog-items-loader";
|
|
import { getAncestors } from "@/lib/services/catalog-tree";
|
|
import { CatalogDetailTabs } from "./catalog-detail-tabs";
|
|
|
|
export default async function CatalogEditPage({
|
|
params,
|
|
}: {
|
|
params: Promise<{ locale: string; id: string }>;
|
|
}) {
|
|
const { id } = await params;
|
|
const { session, permissions } = await getAdminContext();
|
|
if (!canAccess(permissions, PERMS.CATALOG_VIEW, session.user.rank)) {
|
|
redirect("/admin");
|
|
}
|
|
|
|
const pageId = parseInt(id, 10);
|
|
if (Number.isNaN(pageId)) notFound();
|
|
|
|
const [catalogPage] = await db
|
|
.select()
|
|
.from(CatalogPages)
|
|
.where(eq(CatalogPages.id, pageId))
|
|
.limit(1);
|
|
|
|
if (!catalogPage) notFound();
|
|
|
|
const [children, itemsData, ancestors] = await Promise.all([
|
|
db
|
|
.select({
|
|
id: CatalogPages.id,
|
|
caption: CatalogPages.caption,
|
|
enabled: CatalogPages.enabled,
|
|
})
|
|
.from(CatalogPages)
|
|
.where(eq(CatalogPages.parentId, pageId))
|
|
.orderBy(asc(CatalogPages.orderNum)),
|
|
loadCatalogItemsData(pageId),
|
|
getAncestors(catalogPage.parentId),
|
|
]);
|
|
|
|
const {
|
|
items: catalogItems,
|
|
baseItems,
|
|
catalogNameMap,
|
|
furniDataIdList,
|
|
furniDescriptionMap,
|
|
furniRevisionMap,
|
|
interactionTypes,
|
|
allPages,
|
|
gamedataHotel,
|
|
} = itemsData;
|
|
|
|
const canEdit = canAccess(permissions, PERMS.CATALOG_EDIT, session.user.rank);
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* Breadcrumb */}
|
|
<nav className="flex items-center gap-1 text-sm text-muted-foreground">
|
|
<Link
|
|
href={"/admin/catalog"}
|
|
className="hover:text-foreground transition-colors"
|
|
>
|
|
Catalog
|
|
</Link>
|
|
{ancestors.map((bc) => (
|
|
<Fragment key={bc.id}>
|
|
<ChevronRight className="h-3 w-3 flex-shrink-0" />
|
|
<Link
|
|
href={`/admin/catalog/${bc.id}`}
|
|
className="hover:text-foreground transition-colors"
|
|
>
|
|
{bc.caption}
|
|
</Link>
|
|
</Fragment>
|
|
))}
|
|
<ChevronRight className="h-3 w-3 flex-shrink-0" />
|
|
<span className="text-foreground font-medium">
|
|
{catalogPage.caption}
|
|
</span>
|
|
</nav>
|
|
|
|
{/* Title */}
|
|
<div>
|
|
<h1 className="text-3xl font-bold tracking-tight">
|
|
{catalogPage.caption}
|
|
<span className="ml-2 text-base font-normal text-muted-foreground">
|
|
#{catalogPage.id}
|
|
</span>
|
|
</h1>
|
|
<p className="text-muted-foreground">
|
|
Layout: {catalogPage.pageLayout} · {catalogItems.length} items
|
|
</p>
|
|
</div>
|
|
|
|
{/* Tabs */}
|
|
<CatalogDetailTabs
|
|
catalogPage={{
|
|
id: catalogPage.id,
|
|
caption: catalogPage.caption,
|
|
parentId: catalogPage.parentId,
|
|
pageLayout: catalogPage.pageLayout,
|
|
enabled: catalogPage.enabled,
|
|
visible: catalogPage.visible,
|
|
minRank: catalogPage.minRank,
|
|
clubOnly: catalogPage.clubOnly,
|
|
orderNum: catalogPage.orderNum,
|
|
iconImage: catalogPage.iconImage,
|
|
iconColor: catalogPage.iconColor,
|
|
pageHeadline: catalogPage.pageHeadline,
|
|
pageTeaser: catalogPage.pageTeaser,
|
|
pageSpecial: catalogPage.pageSpecial,
|
|
pageText1: catalogPage.pageText1,
|
|
pageText2: catalogPage.pageText2,
|
|
pageTextDetails: catalogPage.pageTextDetails,
|
|
pageTextTeaser: catalogPage.pageTextTeaser,
|
|
}}
|
|
items={catalogItems}
|
|
baseItems={baseItems}
|
|
catalogNameMap={catalogNameMap}
|
|
childPages={children}
|
|
pageId={catalogPage.id}
|
|
canEdit={canEdit}
|
|
furniDataIdList={furniDataIdList}
|
|
furniDescriptionMap={furniDescriptionMap}
|
|
furniRevisionMap={furniRevisionMap}
|
|
allPages={allPages}
|
|
interactionTypes={interactionTypes}
|
|
gamedataHotel={gamedataHotel}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|