96 lines
3.7 KiB
TypeScript
96 lines
3.7 KiB
TypeScript
import Link from 'next/link';
|
||
import type { Route } from 'next';
|
||
import { AlertCircle, Anchor, FileSearch, BadgeDollarSign } from 'lucide-react';
|
||
|
||
import { PageHeader } from '@/components/shared/page-header';
|
||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||
|
||
/**
|
||
* Berths admin index. Both sub-pages (`bulk-add`, `reconcile`) existed
|
||
* pre-2026-05-22 but were only reachable via deep links from inside the
|
||
* Berths list. Surfacing them on a dedicated admin landing tile so the
|
||
* tools are discoverable without prior knowledge of the URL - part of
|
||
* the admin IA regroup (B3 #10 Phase 2).
|
||
*/
|
||
export default async function BerthsAdminIndex({
|
||
params,
|
||
}: {
|
||
params: Promise<{ portSlug: string }>;
|
||
}) {
|
||
const { portSlug } = await params;
|
||
const tools = [
|
||
{
|
||
href: `/${portSlug}/admin/berths/bulk-add` as Route,
|
||
label: 'Bulk add berths',
|
||
description:
|
||
'Generate many berth rows in one wizard - set pier, prefix, mooring number range, and per-berth defaults; preview before commit.',
|
||
icon: Anchor,
|
||
},
|
||
{
|
||
href: `/${portSlug}/admin/berths/reconcile` as Route,
|
||
label: 'Reconciliation queue',
|
||
description:
|
||
"Berths missing required fields after import / PDF parse. Surface what's missing per row and link straight to the edit sheet.",
|
||
icon: FileSearch,
|
||
},
|
||
{
|
||
href: `/${portSlug}/admin/berths/price-reconcile` as Route,
|
||
label: 'Price reconciliation',
|
||
description:
|
||
'Parse the purchase price from each berth’s current spec sheet and review old→new per berth. Approve per row or in bulk; nothing is written until you approve.',
|
||
icon: BadgeDollarSign,
|
||
},
|
||
] as const;
|
||
|
||
return (
|
||
<div className="space-y-6">
|
||
<PageHeader
|
||
title="Berths admin"
|
||
eyebrow="ADMIN"
|
||
description="Tools for bulk berth creation and post-import reconciliation. Single-berth edits stay on the Berths list - these surfaces are for batch operations."
|
||
/>
|
||
|
||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||
{tools.map((t) => {
|
||
const Icon = t.icon;
|
||
return (
|
||
<Link key={t.href} href={t.href} className="block group">
|
||
<Card className="h-full transition-colors group-hover:border-primary/50 group-hover:bg-muted/30">
|
||
<CardHeader className="flex flex-row items-start gap-3 space-y-0 pb-2">
|
||
<Icon
|
||
className="h-5 w-5 mt-0.5 text-muted-foreground group-hover:text-primary"
|
||
aria-hidden
|
||
/>
|
||
<CardTitle className="text-base">{t.label}</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<CardDescription>{t.description}</CardDescription>
|
||
</CardContent>
|
||
</Card>
|
||
</Link>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
<Card className="border-amber-200 bg-amber-50/50">
|
||
<CardHeader className="flex flex-row items-start gap-3 space-y-0 pb-2">
|
||
<AlertCircle className="h-5 w-5 mt-0.5 text-amber-600" aria-hidden />
|
||
<CardTitle className="text-sm">Not what you're looking for?</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<CardDescription className="text-xs">
|
||
For single-berth edits, browse to the{' '}
|
||
<Link
|
||
href={`/${portSlug}/berths` as Route}
|
||
className="font-medium text-primary hover:underline"
|
||
>
|
||
Berths list
|
||
</Link>{' '}
|
||
and click any row. Per-berth PDF uploads + brochure assignment also live there.
|
||
</CardDescription>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
);
|
||
}
|