import { auth } from "@/auth"; import { db } from "@/lib/db"; import { hasPermission } from "@/lib/permissions"; import { notFound, redirect } from "next/navigation"; import Link from "next/link"; import { formatCurrency, formatDate } from "@/lib/utils"; import { EditSiteButton } from "../site-form"; import { SiteCharts } from "./site-charts"; import { ConsumptionForm } from "./consumption-form"; import type { Metadata } from "next"; interface Props { params: Promise<{ id: string }> } export async function generateMetadata({ params }: Props): Promise { const { id } = await params; const site = await db.site.findUnique({ where: { id }, select: { name: true } }); return { title: site?.name ?? "Site Detail" }; } export default async function SiteDetailPage({ params }: Props) { const session = await auth(); if (!session?.user) redirect("/login"); if (!hasPermission(session.user.role, "manage_sites")) redirect("/dashboard"); const { id } = await params; const thirtyDaysAgo = new Date(); thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30); const [site, products] = await Promise.all([ db.site.findUnique({ where: { id }, include: { vessels: { select: { id: true, name: true, isActive: true } }, inventory: { include: { product: { select: { id: true, name: true, code: true } } }, orderBy: { quantity: "desc" }, }, consumption: { where: { date: { gte: thirtyDaysAgo } }, include: { product: { select: { name: true } } }, orderBy: { date: "asc" }, }, purchaseOrders: { select: { id: true, poNumber: true, status: true, totalAmount: true, createdAt: true, vendor: { select: { name: true } } }, orderBy: { createdAt: "desc" }, take: 8, }, }, }), db.product.findMany({ where: { isActive: true }, select: { id: true, name: true, code: true }, orderBy: { name: "asc" } }), ]); if (!site) notFound(); const canEdit = session.user.role === "ADMIN"; // Build chart data: inventory bar const inventoryChartData = site.inventory.map((inv) => ({ name: inv.product.name.length > 20 ? inv.product.name.substring(0, 18) + "…" : inv.product.name, quantity: Number(inv.quantity), })); // Build consumption chart: group by date, sum quantities const consumptionByDate = new Map(); for (const c of site.consumption) { const key = formatDate(c.date); consumptionByDate.set(key, (consumptionByDate.get(key) ?? 0) + Number(c.quantity)); } const consumptionChartData = Array.from(consumptionByDate.entries()).map(([date, qty]) => ({ date, qty })); const STATUS_LABELS: Record = { DRAFT: "Draft", MGR_REVIEW: "Under Review", MGR_APPROVED: "Approved", SENT_FOR_PAYMENT: "Sent for Payment", PAID_DELIVERED: "Paid", CLOSED: "Closed", SUBMITTED: "Submitted", REJECTED: "Rejected", }; return (
{/* Breadcrumb */}
Sites / {site.name}
{/* Header */}
{site.code} {site.isActive ? "Active" : "Inactive"}

{site.name}

{site.address &&

{site.address}

} {site.latitude && site.longitude && (

{site.latitude.toFixed(5)}, {site.longitude.toFixed(5)}

)}
+ Create PO {canEdit && }
{/* Summary cards */}

Assigned Vessels

{site.vessels.length}

Items Tracked

{site.inventory.length}

POs (all time)

{site.purchaseOrders.length}

{/* Charts */} {(inventoryChartData.length > 0 || consumptionChartData.length > 0) && ( )} {/* Inventory table */}

Inventory at this site

{site.inventory.length === 0 ? (

No inventory tracked yet. Updated automatically when POs are delivered here.

) : ( {site.inventory.map((inv) => ( ))}
Item Code Qty on hand Updated
{inv.product.name} {inv.product.code} {Number(inv.quantity)} {formatDate(inv.updatedAt)}
)}
{/* Record consumption */}

Record Daily Consumption

{/* Assigned vessels */} {site.vessels.length > 0 && (

Assigned Vessels (Cost Centres)

{site.vessels.map((v) => ( {v.name} ))}
)} {/* Recent POs */} {site.purchaseOrders.length > 0 && (

Recent Purchase Orders

{site.purchaseOrders.map((po) => ( ))}
PO Vendor Status Amount Date
{po.poNumber} {po.vendor?.name ?? } {STATUS_LABELS[po.status] ?? po.status} {formatCurrency(Number(po.totalAmount))} {formatDate(po.createdAt)}
)}
); }