@ticketboothapp/booking 1.2.188 → 1.2.190

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/package.json +1 -1
  2. package/src/components/booking/AddOnsSection.module.css +124 -0
  3. package/src/components/booking/AddOnsSection.tsx +17 -21
  4. package/src/components/booking/AdminChangeBookingContent.tsx +1 -0
  5. package/src/components/booking/AdminChangeBookingFlow.tsx +1 -0
  6. package/src/components/booking/AdminChangeReceiptComparison.tsx +3 -3
  7. package/src/components/booking/Calendar.module.css +124 -10
  8. package/src/components/booking/Calendar.tsx +46 -20
  9. package/src/components/booking/CancellationPolicySelector.module.css +33 -4
  10. package/src/components/booking/CancellationPolicySelector.tsx +30 -28
  11. package/src/components/booking/ChangeBookingFlow.tsx +1 -0
  12. package/src/components/booking/ChangeBookingItineraryPanel.tsx +3 -0
  13. package/src/components/booking/CollapsibleAddOnItem.module.css +1 -1
  14. package/src/components/booking/ItineraryBox.module.css +14 -0
  15. package/src/components/booking/ItineraryBox.tsx +75 -7
  16. package/src/components/booking/MealDrinkAddOnSelector.tsx +10 -12
  17. package/src/components/booking/NewBookingFlow.tsx +1 -0
  18. package/src/components/booking/PrivateShuttlePassengerSection.tsx +7 -1
  19. package/src/components/booking/ReturnTimeSelector.module.css +23 -4
  20. package/src/components/booking/ReturnTimeSelector.tsx +5 -5
  21. package/src/components/booking/StandardBookingItineraryPanel.tsx +3 -0
  22. package/src/components/booking/TicketSelector.module.css +30 -3
  23. package/src/components/booking/TicketSelector.tsx +6 -6
  24. package/src/hooks/useIsBookingLaunchLive.ts +4 -1
  25. package/src/lib/booking/i18n/messages/en.json +2 -0
  26. package/src/lib/booking/i18n/messages/fr.json +2 -0
  27. package/src/lib/booking-constants.ts +1 -1
  28. package/CHANGE_BOOKING_BE_HANDOFF.md +0 -160
@@ -1,160 +0,0 @@
1
- # Backend handoff: customer change-booking quote (full UI preview)
2
-
3
- This document describes what the **booking API** should return so the website’s customer **self-serve change flow** can show **server-authored** dollar amounts in checkout lines and optional picker overrides.
4
-
5
- Existing endpoint (names may vary in your stack): **`POST …/change/quote`** — response type `ChangeBookingQuoteResponse` in `@ticketboothapp/booking` / shared client types.
6
-
7
- ## Current Pricing V2 alignment
8
-
9
- As of 2026-07-05, the frontend types and visible change-booking preview helpers consume the broader Pricing V2 quote snapshot shape used by the backend:
10
-
11
- - `pricingQuote` / `quote` may carry `PricingQuote`-style fields such as `grossSubtotal`, `discountTotal`, `paymentCreditTotal`, `netSubtotalBeforeTax`, `taxAmount`, `payableTotal`, `balanceDelta`, `amountToCharge`, `refundCandidate`, `lines`, `oldReceiptHash`, and `status`.
12
- - Display helpers prefer server-authored V2 totals and canonical `PricingQuote.lines` when present, then fall back to the existing `newReceipt`, `proposed`, and cent fields.
13
- - Gift-card credit is treated as `paymentCreditTotal` / payment credit in UI copy, not as a discount total. If a quote reports `paymentCreditTotal` without an explicit credit line, the package adds a display-only payment-credit row.
14
- - Change-booking amount-due/refund display prefers `balanceDelta`, `amountToCharge`, and `refundCandidate` from the canonical quote before legacy `amountDueCents` / `priceDiff`.
15
- - Public self-serve and admin/provider change flows clear stale quote totals while changed selections are being re-quoted and use canonical quote charge/refund fields for final payment/free-confirm guards.
16
-
17
- ## Already required for “totals confirmed” UI
18
-
19
- The frontend treats pricing as confirmed when the quote includes receipt-style totals (via `newReceipt` / `proposed` / `newTotalCents`, etc.) and `amountDueCents` or `priceDiff` for the amount owed. That unlocks subtotal/tax/total rows and replaces the pre-quote placeholder block.
20
-
21
- ## Ticket pricing on change (authoritative product rules)
22
-
23
- These rules apply when changing an existing booking for the **same parent catalog product** (self-serve). Use **booking snapshot + original receipt** to know what was sold; use **live catalog** for the **currently selected** departure date and product option.
24
-
25
- ### Inputs (per ticket category `y`)
26
-
27
- | Symbol | Meaning |
28
- | --- | --- |
29
- | `x_y` | Original booked count for category `y` on the **original** booking (protected headcount cap). |
30
- | `lockedUnit_y` | Unit price those tickets were sold at (from receipt / booking line items), major currency units. |
31
- | `liveUnit_y` | Live catalog unit for category `y` at the **currently selected** departure date + product option (+ availability slot as modeled). |
32
- | `q_y` | Current quantity selected in the change UI for category `y`. |
33
-
34
- Define:
35
-
36
- - `protected_y = min(q_y, x_y)` — seats that correspond to **original** tickets still present.
37
- - `incremental_y = max(0, q_y - x_y)` — **new** seats added in this change session.
38
-
39
- Define **unchanged itinerary** as: selected departure **date** equals the original booking’s date **and** selected **product option** equals the original booking’s product option (same IDs / same comparison rules you use elsewhere for “same PO”).
40
-
41
- ### Rule A — unchanged itinerary (same date **and** same product option)
42
-
43
- For each category `y`:
44
-
45
- - **`protected_y` seats:** unit price is **`lockedUnit_y` exactly** — no adjustment up or down based on today’s catalog. Catalog price changes **do not** move those seats.
46
- - **`incremental_y` seats:** unit price is **`liveUnit_y`** (live catalog for the current selection).
47
-
48
- Adding passengers or changing **return** does **not** re-price those protected seats; only net-new seats follow live catalog. **Return add-ons** keep the separate return-floor behavior already agreed (per-person floor from what was paid; incremental passengers pay live return pricing where applicable).
49
-
50
- ### Rule B — itinerary changed (date changed **or** product option changed)
51
-
52
- For each category `y`:
53
-
54
- - **`protected_y` seats:** unit price is **`max(lockedUnit_y, liveUnit_y)`** — they never go **below** what they paid (**floor**), but they **may go up** if the new date or option prices higher.
55
- - **`incremental_y` seats:** unit price is **`liveUnit_y`**.
56
-
57
- ### Fees
58
-
59
- Fee lines should follow the **same structural split** as tickets (protected vs incremental headcount). Align fee formulas with whatever you implement alongside these ticket rules.
60
-
61
- ### Backend / reconciliation
62
-
63
- `POST …/change/quote` should compute ticket line totals with **Rule A vs Rule B** from **server-held booking state + selected date/PO + live catalog**, not from trusting the browser alone. **`clientProposedTotal`** remains a cross-check when the client sends it.
64
-
65
- ### Current website package (FYI)
66
-
67
- The `@ticketboothapp/booking` change flow implements Rule **A** vs **B** for ticket and config-fee lines when self‑serve receipt pricing applies (same parent product): **exact** receipt units on protected seats/fees when calendar date **and** product option match the booking; otherwise **`max(locked, live)`** for protected headcount.
68
-
69
- ---
70
-
71
- ## Recommended fields for server-owned detail
72
-
73
- Pickers show **catalog** prices by default (same booking **currency** as the original receipt — the change UI does not switch currency). These optional fields **override** display when present on the quote:
74
-
75
- 1. **`ticketUnitPriceByCategory`** — `Record<string, number>`
76
- - Keys: ticket categories (`ADULT`, `CHILD`, …), uppercase preferred.
77
- - Values: **unit price in major units** (e.g. dollars), display currency.
78
- - When present, these update ticket **picker** display units on self‑serve change; totals must still follow **Rule A / Rule B** above unless the quote fully replaces breakdown.
79
-
80
- 2. **Line items** — `pricingQuote.lines` / `quote.lines`, then `newReceipt.lineItems` or `proposed.lineItems` (fallback `original`)
81
- - Pricing V2 shape: `{ lineId?, label?, amount?, quantity?, type?, billable?, taxBehavior?, discountBehavior?, source?, metadata? }`.
82
- - Legacy receipt shape: `{ label?, amount?, type?, quantity? }`.
83
- - Mapped to checkout **`PriceSummary`** rows when present; non-billable Pricing V2 lines are omitted from the primary payable summary. Otherwise checkout falls back to FE-built lines after totals confirm.
84
-
85
- ### Additional optional maps
86
-
87
- | Field | Purpose |
88
- | --- | --- |
89
- | **`returnOptionPriceByReturnAvailabilityId`** | `Record<returnAvailabilityId, number>` — **per-person** return add-on in major units; overrides catalog return card amounts for matching ids. The FE still **floors** per-person return at what was paid on the original receipt when applicable — values below that floor are raised client-side. |
90
- | **`cancellationPolicyFeeByPolicyId`** | Optional passthrough on the quote type / `serverPreview` for future use or tooling. **Not used** to drive cancellation UI in change flow today — cancellation policy is **fixed** to the existing booking; there is no policy picker. |
91
-
92
- ## Notes for implementers
93
-
94
- - **`clientProposedTotal`** (existing): FE still sends this as a hint for reconciliation; display should follow **quote response**, not the client-only cart.
95
- - **Currency**: align optional maps and line `amount` values with `currency` / receipt currency; change booking stays in the booking’s sold currency end-to-end on FE.
96
- - **Cancellation policy on change**: FE sends the booked policy on reserve/confirm paths; it is **not** chosen from product config during change — preserve the booking’s policy server-side unless product rules say otherwise.
97
- - **`serverPreview.completeness`**: the package sets this to **`full`** when mapped quote lines are available and **`totals_only`** when only totals are available. UI does not gate progression on this field.
98
-
99
- ---
100
-
101
- ## Admin / provider manual line items (signed adjustments)
102
-
103
- **Frontend (this package):** `AdminChangeBookingFlow` lets staff add custom receipt lines (label + signed amount). The same values are:
104
-
105
- 1. **`POST …/change/quote`** — optional request field **`manualLineAdjustments`**: `Array<{ label: string; amount: number }>` in **major units** (same currency as the booking). Amounts are signed (credits negative). Omitted when there are no custom lines.
106
- 2. **Provider apply** — `onChangeBooking` payload field **`pricingAdjustment`**, with **`mode: 'MANUAL_LINES'`** and **`additionalAdjustments`** equal to the **provider** inline editor rows **plus** these admin custom lines (concatenated). `newTotalAmount` remains the full proposed total (already includes those lines on the client).
107
-
108
- **Backend expectations**
109
-
110
- - **Quote:** When `manualLineAdjustments` is present, add each line to the server’s priced subtotal (before tax) for the change intent, and return quote totals / `amountDue` / line items that **include** these rows so the UI and `clientProposedTotal` stay in tolerance.
111
- - **Provider change API:** When `pricingAdjustment.additionalAdjustments` includes the same rows, persist them on the new receipt and charge the **same** total as `newTotalAmount` (within your rounding rules).
112
-
113
- If the server ignores `manualLineAdjustments` or `additionalAdjustments`, the customer will see the FE total but pay a different amount.
114
-
115
- ---
116
-
117
- ## Admin FE-authoritative quote path (new)
118
-
119
- For provider dashboard / admin tooling, we need a dedicated quote route where the **frontend is authoritative** for
120
- the full receipt preview (totals + line items), and BE does not re-price those values.
121
-
122
- ### Endpoint
123
-
124
- - **`POST /1/admin/bookings/:bookingReference/change/quote?lastName=...`**
125
-
126
- Keep the public self-serve endpoint unchanged.
127
-
128
- ### Request contract (admin)
129
-
130
- Same selection fields as `ChangeBookingQuoteRequest`, plus:
131
-
132
- - `feReceipt`:
133
- - `subtotal` (major units)
134
- - `tax` (major units)
135
- - `total` (major units)
136
- - `currency?`
137
- - `lineItems: Array<{ label?: string; amount?: number; type?: string; quantity?: number }>`
138
- - `feAmountDueMajorUnits?` (optional signed delta the FE displays; `newTotal - previousTotal`)
139
-
140
- For admin/provider cross-product changes, FE also sends:
141
-
142
- - `newParentProductId`: destination parent catalog product id (`p_...`)
143
- - `newProductId`: destination product option id selected from availability (`po_...` or equivalent), preserved for existing quote/apply compatibility
144
-
145
- BE should persist both the destination parent product and selected option when applying the change. Capacity checks,
146
- receipt pricing, add-ons, pickup locations, and itinerary display should resolve against `newParentProductId` +
147
- `newProductId`, not the booking’s original product. Same-parent receipt-floor rules continue only when the booking
148
- parent product equals `newParentProductId`; cross-parent changes should price from the destination catalog / FE
149
- authoritative admin receipt path.
150
-
151
- ### Backend expectations
152
-
153
- - Validate admin auth + booking/availability eligibility only.
154
- - Persist `feReceipt` on the change intent as the quote source-of-truth.
155
- - Return a `ChangeBookingQuoteResponse`-compatible payload using the stored FE receipt:
156
- - `newReceipt` / `proposed` line items from `feReceipt.lineItems`
157
- - `newReceipt.subtotal/tax/total` from `feReceipt`
158
- - `amountDueCents` / `balanceDeltaMajorUnits` / `priceDiff` coherent with stored totals
159
- - `changeIntentId`, `canProceed`, `reasonIfBlocked`
160
- - Payment intent + apply/confirm for this change intent must use persisted FE totals/lines (no repricing).