"use client"; /** * RecordHeader — header block that the core editor's PageView renders INSTEAD * of the plain page title when `page.meta.isRecord` is true. * * A record's page is a normal page whose identity is 1:1 with a * database_record (via `database_records.pageId`). This header shows the * record's icon/title plus its properties in a clean, readable grid so the * page reads as a "record" rather than a blank doc. * * CONTRACT (core PageView → this component): * * When only `recordId` is given (no databaseId), the record is fetched by id * and its own `databaseId` used for the property schema. */ import { useEffect, useState } from "react"; import { useQuery } from "@tanstack/react-query"; import { Loader2 } from "lucide-react"; import { apiFetch } from "@/lib/api"; import { DatabaseDto, DatabaseProperty, RecordDto, useDatabase } from "@/hooks/use-database"; import { CellRenderer } from "@/components/database/cell-renderer"; import { CellEditor } from "@/components/database/cell-editor"; export interface RecordHeaderProps { /** Record id (database_records.id). */ recordId?: string; /** Database the record belongs to (enables property-schema fetch). */ databaseId?: string; /** Pass the full record DTO directly to skip the fetch. */ record?: RecordDto; /** Pass properties directly to skip the schema fetch. */ properties?: DatabaseProperty[]; readOnly?: boolean; className?: string; } function unwrap(body: unknown): T { const b = body as { data?: T } | null; if (b && typeof b === "object" && "data" in (b as Record)) { return (b as { data: T }).data; } return body as T; } const SKIP_TYPES = new Set(["button"]); export function RecordHeader({ recordId, databaseId: dbIdProp, record: recordProp, properties: propsProp, readOnly, className }: RecordHeaderProps) { // Single, unconditional fetch — always by record id (the canonical source). const { data: fetched, isLoading } = useQuery({ queryKey: ["record-fresh", recordId ?? recordProp?.id], enabled: !!(recordId ?? recordProp?.id), queryFn: async () => unwrap(await apiFetch(`/records/${recordId ?? recordProp!.id}`)) }); // Resolve database id from the record when not provided. const effectiveRecord: RecordDto | undefined = fetched ?? recordProp; const databaseId = dbIdProp ?? effectiveRecord?.databaseId; const { data: database } = useDatabase(databaseId); const properties = propsProp ?? (database?.properties.filter((p) => !SKIP_TYPES.has(p.type)) as DatabaseProperty[]); if (!effectiveRecord) { return (
{isLoading ? "Loading record…" : "Record unavailable"}
); } const titleProp = properties?.find((p) => p.isTitle) ?? properties?.find((p) => p.type === "title"); const header = (
{effectiveRecord.icon ?? "📄"}
{titleProp ? ( undefined} className="text-3xl font-bold" /> ) : (

Record

)}
); if (!properties || properties.length === 0) return
{header}
; const fields = properties.filter((p) => p !== titleProp); return (
{header} {fields.length > 0 && (
{fields.map((p) => (
{p.name}
{readOnly ? ( ) : ( undefined} /> )}
))}
)}
); }