/** * Mutually exclusive lifecycle phase. Exactly one at any time. * Drives the primary status chip on the job card. */ export type JobLifecycle = 'Upcoming' | 'AwaitingUpdate' | 'AtOrigin' | 'InProgress' | 'Arriving' | 'Arrived' | 'Complete' | 'Cancelled'; /** * Non-exclusive health signals. Zero or more apply at once. */ export type JobHealthSignal = 'OnTrack' | 'Delayed' | 'DelayedStart' | 'NotReporting' | 'RuleViolation' | 'LowBattery'; /** * Arrival evidence state. Mutually exclusive. */ export type JobProofState = 'NotArrived' | 'FirstObserved' | 'ArrivalConfirmed' | 'Unknown'; /** Derived when lifecycle reaches Complete. */ export type JobOutcome = 'on_time' | 'late' | 'early'; export interface JobRule { id: string; kind: string; draftKind?: string; config?: Record; violated?: boolean; violationDetail?: string; violatedAt?: string; } export interface JobRecipientChannels { emailNotification: boolean; smsNotification: boolean; pushNotification: boolean; appNotification: boolean; } export interface JobRecipients { allUsers?: (JobRecipientChannels & { isEnabled: boolean; }) | null; roles?: Array; users?: Array; external?: Array<{ type: 'email' | 'sms'; recipient: string; isEnabled?: boolean; }>; } /** * `customer_note` and `operator_note` are the two halves of the customer SMS * thread — inbound from the customer's phone, outbound from the dispatcher — * and carry the message body in `title`. The rest are job milestones. */ export type JobTimelineKind = 'now' | 'alert' | 'info' | 'customer_note' | 'operator_note'; export interface JobTimelineEvent { id: string; title: string; time: string; kind?: JobTimelineKind; /** Who sent an `operator_note`. Unset on milestones and on customer notes. */ author?: string; } /** * Const value namespace for {@link JobLifecycle}. Use these instead of inline * string literals so call sites don't drift if the enum is ever renamed. */ export declare const JobLifecycleValue: { readonly Upcoming: "Upcoming"; readonly AwaitingUpdate: "AwaitingUpdate"; readonly AtOrigin: "AtOrigin"; readonly InProgress: "InProgress"; readonly Arriving: "Arriving"; readonly Arrived: "Arrived"; readonly Complete: "Complete"; readonly Cancelled: "Cancelled"; }; /** Const value namespace for {@link JobHealthSignal}. */ export declare const JobHealthSignalValue: { readonly OnTrack: "OnTrack"; readonly Delayed: "Delayed"; readonly DelayedStart: "DelayedStart"; readonly NotReporting: "NotReporting"; readonly RuleViolation: "RuleViolation"; readonly LowBattery: "LowBattery"; }; /** Const value namespace for {@link JobProofState}. */ export declare const JobProofStateValue: { readonly NotArrived: "NotArrived"; readonly FirstObserved: "FirstObserved"; readonly ArrivalConfirmed: "ArrivalConfirmed"; readonly Unknown: "Unknown"; }; /** Const value namespace for {@link JobOutcome}. */ export declare const JobOutcomeValue: { readonly OnTime: "on_time"; readonly Late: "late"; readonly Early: "early"; }; /** Const value namespace for {@link JobTimelineKind}. */ export declare const JobTimelineKindValue: { readonly Now: "now"; readonly Alert: "alert"; readonly Info: "info"; readonly CustomerNote: "customer_note"; readonly OperatorNote: "operator_note"; }; /** * V1 rule kinds. The `kind` column on {@link JobRule} is stored as a free-form * string (JSON-embedded) so the entity type doesn't constrain it directly; this * namespace is the contract callers should hold themselves to. */ export declare const JobRuleKindValue: { readonly Stop: "stop"; readonly Zone: "zone"; readonly Eta: "eta"; readonly Window: "window"; readonly Speed: "speed"; readonly Deviation: "deviation"; }; export type JobRuleKind = (typeof JobRuleKindValue)[keyof typeof JobRuleKindValue]; export declare const ACTIVE_JOB_LIFECYCLES: ReadonlySet; export declare class Job { id: number; clientId: number; imei: string; name: string; reference: string | null; /** Customer's mobile number (E.164) — the editable "current" number; each customer link snapshots its own. */ customerPhone: string | null; lifecycle: JobLifecycle; healthSignals: JobHealthSignal[] | null; proofState: JobProofState; outcome: JobOutcome | null; startLat: number | null; startLng: number | null; startLabel: string | null; startDetail: string | null; startRadiusM: number; endLat: number | null; endLng: number | null; endLabel: string | null; endDetail: string | null; endRadiusM: number; scheduledStart: Date | null; targetArrival: Date | null; startedAt: Date | null; firstObservedAt: Date | null; arrivedAt: Date | null; completedAt: Date | null; cancelledAt: Date | null; pingsInEndZone: number; lastPositionAt: Date | null; lastEvaluatedAt: Date | null; etaArrivalAt: Date | null; etaUpdatedAt: Date | null; etaDriveSeconds: number | null; etaDistanceMeters: number | null; originalEtaDriveSeconds: number | null; /** Per-job override of the account-level customer-page ETA window buffer. */ etaWindowBufferMinutes: number | null; rules: JobRule[] | null; timeline: JobTimelineEvent[] | null; recipients: JobRecipients | null; liveLinkToken: string | null; showAttachmentsOnLiveLink: boolean; /** Stashed cadence captured when lifecycle entered Arriving — null otherwise. */ priorMovingFrequency: number | null; priorStoppedFrequency: number | null; createdBy: string; createdAt: Date; modifiedBy: string | null; modifiedAt: Date | null; deletedAt: Date | null; deletedBy: string | null; }