import { type ReactNode } from "react"; import { type BookingRecord } from "../index.js"; import { type TimelineEvent } from "./booking-activity-timeline.js"; import { type BookingItemResourceKind } from "./booking-item-list.js"; import { type BookingPaymentsSummaryRow } from "./booking-payments-summary.js"; /** * Optional extra tab. When provided, the canonical layout renders a * trigger and a content panel. Modeled after PersonDetailPage's * commercial-tab slot shape. The trigger label falls back to the i18n * default (`messages.bookingDetailPage.tabInvoices` etc.). */ export interface BookingDetailTabSlot { label?: string; /** Receives the loaded booking so the slot can use sell amount, ids, etc. */ content: BookingDetailSlotContent; } export type BookingDetailSlotContent = ReactNode | ((booking: BookingRecord) => ReactNode); export interface BookingDetailPageSlots { /** Rendered between the title row and the summary card. */ header?: (booking: BookingRecord) => ReactNode; /** Rendered between the summary card and the tabs. */ afterSummary?: (booking: BookingRecord) => ReactNode; overviewStart?: (booking: BookingRecord) => ReactNode; overviewEnd?: (booking: BookingRecord) => ReactNode; travelersStart?: (booking: BookingRecord) => ReactNode; financeStart?: (booking: BookingRecord) => ReactNode; /** Replaces the default finance-tab `BookingPaymentsSummary` card. */ paymentsContent?: BookingDetailSlotContent; financeEnd?: (booking: BookingRecord) => ReactNode; documents?: (booking: BookingRecord) => ReactNode; activityEnd?: (booking: BookingRecord) => ReactNode; /** Mounts a dedicated `Invoices` tab between Payments and Suppliers. */ invoicesTab?: BookingDetailTabSlot; /** * Extra events merged into the Activity-tab timeline. Operator * templates pass action-ledger entries here so the timeline stays a * single chronological feed. */ activityExtraEvents?: readonly TimelineEvent[]; /** Rendered below the activity timeline events — typically a "load more" pager. */ activityTimelineFooter?: ReactNode; } /** Tab values used by the canonical `BookingDetailPage`. */ export type BookingDetailTabValue = "items" | "travelers" | "finance" | "invoices" | "documents" | "suppliers" | "activity" | "metadata"; export interface BookingDetailPageProps { id: string; className?: string; locale?: string; /** When true, the inline `Bookings > #` breadcrumb is suppressed * (use when the host shell already renders breadcrumbs). */ hideBreadcrumb?: boolean; onBack?: () => void; /** * Forwarded to the finance-tab `BookingPaymentsSummary` header as a * `Record payment` action button. */ onRecordPayment?: (booking: BookingRecord) => void; /** * When set, the Record payment header button renders disabled and its * tooltip shows this reason. Use for "nothing left to pay" states. */ recordPaymentDisabledReason?: string | null; /** * When set, the Add schedule button in the payment-schedule section * renders disabled and its tooltip shows this reason. */ addScheduleDisabledReason?: string | null; /** * Amount the customer has paid so far against this booking, in cents * of `booking.sellCurrency`. When provided, a `Paid` stat is shown * next to `Total`. Resolution (invoices vs. raw payments) is left to * the host template — `bookings-ui` doesn't fetch finance data. */ paidAmountCents?: number | null; /** * True when the host has found at least one recorded customer payment. Kept * separate from `paidAmountCents` because host invoice summaries can be * paginated while the cancellation settlement path checks all paid invoices. */ hasRecordedPayment?: boolean; /** * Open a linked resource referenced by a booking item (product or * availability slot) in the host app. When omitted, the item-snapshot * sheet renders the names as plain text. */ onItemResourceOpen?: (kind: BookingItemResourceKind, id: string) => void; /** Open the linked CRM person's detail page (used by the Payer card). */ onPersonOpen?: (personId: string) => void; /** Open the linked CRM organization's detail page (used by the Payer card). */ onOrganizationOpen?: (organizationId: string) => void; /** * Open an invoice in-place when the operator clicks the invoice * number in the Payments row. Typically wired to a `Sheet` that * renders the invoice-detail view so the admin doesn't leave the * booking screen. */ onInvoiceOpen?: (invoiceId: string, row: BookingPaymentsSummaryRow) => void; /** Forwarded to the finance-tab `BookingPaymentsSummary` row menu. */ onViewPayment?: (row: BookingPaymentsSummaryRow) => void; /** Forwarded to the finance-tab `BookingPaymentsSummary` row menu. */ onEditPayment?: (row: BookingPaymentsSummaryRow) => void; /** Forwarded to the finance-tab `BookingPaymentsSummary` row menu. */ onDeletePayment?: (row: BookingPaymentsSummaryRow) => Promise | void; /** * Controlled active-tab value. Hosts wire this to their router so * the active tab can be reflected in the URL (`?tab=activity` etc.) * and the page reloads to the right tab when a link is shared. * Leave both `activeTab` + `onTabChange` undefined for uncontrolled * mode (defaults to `overview`). */ activeTab?: BookingDetailTabValue; /** Fires when the user switches tabs. Hosts push the new value into the URL. */ onTabChange?: (tab: BookingDetailTabValue) => void; slots?: BookingDetailPageSlots; } export declare function BookingDetailPage({ id, className, locale, hideBreadcrumb, onBack, onRecordPayment, recordPaymentDisabledReason, addScheduleDisabledReason, paidAmountCents, hasRecordedPayment, onItemResourceOpen, onPersonOpen, onOrganizationOpen, onInvoiceOpen, onViewPayment, onEditPayment, onDeletePayment, activeTab, onTabChange, slots, }: BookingDetailPageProps): import("react").JSX.Element; /** * Billing/contact card for the Travelers tab. Snapshot fields on the * booking row are the source of truth (they capture contact info at * the time of booking). When they're empty — typically for bookings * created via flows that don't snapshot — fall back to the linked CRM * person / organization so the operator still sees who they're * billing. */ export declare function BookingBillingContextCard({ booking, onPersonOpen, onOrganizationOpen, }: { booking: BookingRecord; /** Open the linked CRM person's detail page. */ onPersonOpen?: (personId: string) => void; /** Open the linked CRM organization's detail page. */ onOrganizationOpen?: (organizationId: string) => void; }): import("react").JSX.Element;