import * as React from "react"; export type TravelerRole = "lead" | "adult" | "child" | "infant"; export type TravelerUnitAssignmentSource = "auto" | "manual" | "none"; export interface TravelerEntry { /** Stable client-side identity used by item/extra travelerKeys links. */ clientTravelerKey?: string; personId: string | null; firstName: string; lastName: string; email: string; /** Snapshotted from the linked person at pick time. Optional. */ phone: string; /** Snapshotted from the linked person at pick time. Optional. */ preferredLanguage: string; role: TravelerRole; /** ISO `YYYY-MM-DD` date of birth. Drives age-derived unit assignment. */ dateOfBirth: string | null; /** option_unit_id of the person pricing tier this traveler is billed as. */ pricingUnitId: string | null; /** pricing_category_id selected from the product's traveler price matrix, when applicable. */ pricingCategoryId: string | null; /** Operator intent for `pricingCategoryId`; preserves an explicit category across CRM edits. */ pricingCategorySource?: TravelerUnitAssignmentSource; /** option_unit_id of the room/vehicle this traveler occupies, when applicable. */ inventoryUnitId: string | null; /** Operator intent for `pricingUnitId`; defaults to `auto` when omitted. */ pricingUnitSource?: TravelerUnitAssignmentSource; /** Operator intent for `inventoryUnitId`; defaults to `auto` when omitted. */ inventoryUnitSource?: TravelerUnitAssignmentSource; } export interface TravelerListValue { travelers: TravelerEntry[]; } export declare const emptyTravelerListValue: TravelerListValue; /** Factory for a blank row — `role` defaults to `adult` unless the list is empty. */ export declare function createBlankTraveler(role?: TravelerRole): TravelerEntry; export declare function insertPersonTraveler(travelers: TravelerEntry[], traveler: TravelerEntry): TravelerEntry[]; export { computeAgeYears } from "@voyant-travel/bookings/pricing-assignment"; /** * Derive the age-banded traveler role from DOB. Falls back to `adult` * when DOB is missing so partial entries still typecheck downstream. * * Thresholds: * - infant: < 2 * - child: 2 – 17 * - adult: 18+ */ export declare function deriveTravelerRoleFromDob(dob: string | null): TravelerRole; export declare function categoryMatchesDob(category: TravelerPricingCategoryOption, dob: string | null): boolean; export declare function matchPricingCategoryForTraveler(categories: ReadonlyArray | undefined, dob: string | null, role: TravelerRole | null, inventoryUnitId: string | null): string | null; export declare function applyTravelerPricingCategory(traveler: TravelerEntry, category: TravelerPricingCategoryOption): Partial; export interface RoomUnitOption { unitId: string; unitName: string; /** * How many more travelers can be assigned to this unit. Decremented by * the parent based on the stepper's quantity × occupancy capacity minus * travelers already assigned to that unit. */ remainingCapacity: number; } /** * Per-option breakdown of the actual age-banded units the product * configures. Lets the row render dynamic category buttons (e.g. * Adult/Child/Senior for one product, Adult/Child/Infant for another) * rather than a hardcoded set. */ export interface RoomGroupUnit { unitId: string; /** Short label — typically the unit's own name (Adult, Child, Senior). */ unitName: string; /** Stable code (ADULT, CHILD, SENIOR, INFANT, …) when configured. */ unitCode: string | null; minAge: number | null; maxAge: number | null; unitType: "person" | "group" | "room" | "vehicle" | "service" | "other" | null; } export interface RoomGroup { /** option_id this group of units belongs to. */ optionId: string; /** Display name for the option (e.g. "Standard double"). */ optionName: string; /** Default unit when the option is first picked (typically the ADULT-coded row). */ primaryUnitId: string; units: RoomGroupUnit[]; } export interface TravelerPricingCategoryOption { categoryId: string; name: string; code: string | null; categoryType: string; minAge: number | null; maxAge: number | null; unitIds: string[]; } export interface TravelersSectionProps { value: TravelerListValue; onChange: (value: TravelerListValue) => void; /** * Rooms the operator has selected (from OptionUnitsStepperSection + occupancy). * When provided, each traveler gets a room-assignment dropdown. */ roomUnits?: RoomUnitOption[]; /** * Per-option breakdown of all units the product configures. Drives * dynamic category buttons (Adult/Child/Senior or whatever the * product configures) and DOB-aware unit pre-selection on attach. * Required for category buttons to render. */ roomGroups?: RoomGroup[]; /** * Product pricing categories surfaced by the room x traveler price matrix. * Room-only accommodation products use these as the traveler category select. */ pricingCategories?: TravelerPricingCategoryOption[]; billingPersonId?: string | null; labels?: { heading?: string; addTraveler?: string; firstName?: string; lastName?: string; email?: string; role?: string; category?: string; dateOfBirth?: string; roleLead?: string; roleAdult?: string; roleChild?: string; roleInfant?: string; room?: string; noRoom?: string; remove?: string; empty?: string; person?: string; personSearchPlaceholder?: string; personEmpty?: string; createNewPerson?: string; createPersonSheetTitle?: string; editPerson?: string; editPersonSheetTitle?: string; addBillingPerson?: string; relatedPeopleHeading?: string; addRelatedPerson?: string; }; } /** * Traveler list for booking-create flows. Each row can point at an existing * CRM person, create a new CRM person, or carry manual name/email details, * plus role and optional room assignment. * * ### Parent contract * * At submit time, the parent: * 1. Inserts a `booking_travelers` row per traveler with `participantType` * derived from the role (`lead` / `adult` → traveler; `child` / `infant` * → traveler with travelerCategory set). * 2. Carries `personId` through when the traveler is tied to CRM, including * when the payer is also traveling. * 3. Exactly one row should have `role: "lead"` — enforced at submit, not * here. The UI lets the operator pick whichever layout they want, then * the submit handler errors if the invariant isn't met. */ export declare function TravelersSection({ value, onChange, roomUnits, roomGroups, pricingCategories, billingPersonId, labels, }: TravelersSectionProps): React.JSX.Element;