import 'rollup-plugin-inject-process-env'; import { ClockTime, FormDateTimeInput, TimeOffering, TimeSlotSchedule } from "stentor-models"; /** * Minutes between generated starts when the schedule does not say. */ export declare const DEFAULT_SLOT_MINUTES = 30; /** * How far ahead the calendar reaches when the schedule does not say. */ export declare const DEFAULT_HORIZON_DAYS = 60; /** * Field name the chosen date is submitted under when the field does not say. * * Deliberately fixed rather than derived from the field's own name: every existing lead * consumer already reads `preferred_date`, and namespacing it per field would break all of * them to solve a problem only a two-DATETIME step has. A step carrying two of these must * set `dateFieldName` on at least one, or the second silently overwrites the first. */ export declare const DEFAULT_DATE_FIELD_NAME = "preferred_date"; /** * Field name the combined ISO timestamp is submitted under when the field does not say. * * Fixed for the same reason as {@link DEFAULT_DATE_FIELD_NAME}, and additionally because * `datetime` is the name the lead analyzer already recognises and ISO-validates. See * `dateTimeFieldName` to move it. */ export declare const DEFAULT_DATE_TIME_FIELD_NAME = "datetime"; /** * Field name the schedule's timezone is submitted under when the field does not say. * * Fixed for the same reason as {@link DEFAULT_DATE_FIELD_NAME}. It exists so a consumer * can tell a picker-produced `datetime` from a scraped one: an abandoned form contributes * fields literally named `date` or `appointment_time` straight into the lead with no * validation, and "carries an offset" cannot say who produced the value. This can. */ export declare const DEFAULT_TIME_ZONE_FIELD_NAME = "preferred_time_zone"; /** * `FormDateTimeInput` with the name its timezone field is submitted under. * * Declared here rather than read off the model because `timeZoneFieldName` is newer than * the `stentor-models` pinned by this package; it collapses back into `FormDateTimeInput` * once that version lands. */ export interface FormDateTimeInputWithTimeZone extends FormDateTimeInput { /** * Field name the schedule's IANA timezone is submitted under. Defaults to * "preferred_time_zone". */ timeZoneFieldName?: string; } /** * The calendar date a `Date` represents, as "YYYY-MM-DD". * * Read off the local fields rather than through `toISOString`, which converts to UTC and * so reports the next day for an evening selection anywhere west of Greenwich. */ export declare function toCalendarDate(date: Date): string; /** * Whether a zone can actually be used to place a wall-clock time. * * A schedule's zone is typed in by hand in Studio, so "Eastern" or "America/New York" * reaches the picker as readily as a real IANA identifier does. Matching is case * insensitive, so "America/New_york" is fine. */ export declare function isUsableTimezone(timezone?: string): boolean; /** * The zone the visitor's own browser is in, or "" where that cannot be determined. */ export declare function hostTimezone(): string; /** * A zone named the way a visitor reads it, e.g. "America/New_York" to "Eastern Time". * * Falls back to the identifier itself rather than to nothing, because an unnamed zone * still tells a visitor more than silence does. */ export declare function formatTimezoneLabel(timezone?: string): string; /** * An offset-bearing ISO 8601 timestamp for a wall-clock time in the given zone, e.g. * "2026-08-24T09:30:00-04:00". The offset is the one in force on that date, so the value * survives a daylight-saving transition. */ export declare function toOffsetIso(calendarDate: string, clock: ClockTime, timezone: string): string; /** * The zone the picker really built its times in, as the IANA identifier the schedule * authored - or nothing at all when it did not. * * {@link zonedInstant} and {@link toOffsetIso} both fall back to the host's zone rather * than throwing at a visitor mid-form, so an absent or unrecognised `timezone` still * produces a full column of times: they are simply the wrong ones. Naming the business's * zone beside those would hand a consumer a marker it cannot trust, and a wrong marker is * worse than none - the entire point of the field is that it can be trusted - so nothing * is reported instead. * * A fixed offset is refused for the same reason. `Intl` accepts "-04:00", so the times * generated from it are self-consistent, but an offset does not survive a daylight-saving * transition and so cannot stand in for the zone. */ export declare function timeZoneOf(schedule: TimeSlotSchedule): string | undefined; /** * What an offering reads as in the time column - and, because the label is what the field * submits, what a CRM or lead consumer receives for it. */ export declare function formatOfferingLabel(offering: TimeOffering): string; /** * How far ahead the calendar reaches, so the picker's own maxDate and the selectability * rules cannot drift apart. */ export declare function horizonDaysOf(schedule: TimeSlotSchedule): number; /** * The times a schedule offers on one calendar date. * * Slots come from the schedule alone - there is no availability lookup behind this, so a * date change repaints the column without a round trip. The rules, in order: * * 1. `offerings` present replaces generation. `days`, `slotMinutes` and `durationMinutes` * are not consulted. A closing exception still closes the date, because that is the * only way a fixed offering list can express a holiday. * 2. Otherwise the weekday's spans, or the spans of an `exceptions` entry for this exact * date, which *replace* the weekday's rather than adding to them. No spans is closed. * 3. Each span is walked in `slotMinutes` steps, up to but not including its end. * 4. `durationMinutes` gives every offering an `end`; without it they are discrete starts. * A start whose appointment would run past the span's end is not offered at all. * 5. Whatever survives is filtered against now, plus `leadTimeMinutes` if the schedule * sets one. A time earlier today is never offered. * * @param schedule The schedule to read. * @param date The calendar day being offered, read off its local fields. * @param now The current moment. Injectable so the lead-time filter is testable. */ export declare function generateOfferings(schedule: TimeSlotSchedule, date: Date, now?: Date): TimeOffering[]; /** * Whether the calendar should let a date be picked. * * False for anything outside the horizon - in the past, or further ahead than * `horizonDays` - and for any date the schedule generates no offerings for, so a closed * day greys out rather than opening onto an empty column. * * @param schedule The schedule to read. * @param date The calendar day being tested, read off its local fields. * @param now The current moment. Injectable so the horizon is testable. */ export declare function isDateSelectable(schedule: TimeSlotSchedule, date: Date, now?: Date): boolean; /** * The soonest day the calendar would let someone pick, or nothing. * * Deliberately expressed as a walk over {@link isDateSelectable} rather than by * reasoning about the schedule's shape: the answer must be a day the calendar * itself would enable, and duplicating that rule is how the two drift into * offering a date that then greys out. * * Bounded by the schedule's own horizon, so an empty schedule -- or one whose * every remaining day is full -- terminates and returns undefined rather than * searching forever. * * @param schedule The schedule to read. * @param now The current moment. Injectable so the horizon is testable. * @param isBusy Days the CRM has declared full, tested one at a time. */ export declare function firstSelectableDate(schedule: TimeSlotSchedule, now?: Date, isBusy?: (date: Date) => boolean): Date | undefined;