@voyantjs/flights-ui 0.35.0 → 0.37.1

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 (56) hide show
  1. package/dist/components/airport-combobox.d.ts.map +1 -1
  2. package/dist/components/airport-combobox.js +4 -2
  3. package/dist/components/flight-baggage-step.d.ts.map +1 -1
  4. package/dist/components/flight-baggage-step.js +29 -18
  5. package/dist/components/flight-billing-step.d.ts.map +1 -1
  6. package/dist/components/flight-billing-step.js +30 -24
  7. package/dist/components/flight-booking-journey.d.ts.map +1 -1
  8. package/dist/components/flight-booking-journey.js +15 -26
  9. package/dist/components/flight-booking-ledger.d.ts.map +1 -1
  10. package/dist/components/flight-booking-ledger.js +22 -12
  11. package/dist/components/flight-booking-page.js +12 -12
  12. package/dist/components/flight-booking-shell.d.ts.map +1 -1
  13. package/dist/components/flight-booking-shell.js +54 -29
  14. package/dist/components/flight-contact-form.d.ts.map +1 -1
  15. package/dist/components/flight-contact-form.js +7 -3
  16. package/dist/components/flight-fare-upsell-step.d.ts.map +1 -1
  17. package/dist/components/flight-fare-upsell-step.js +58 -30
  18. package/dist/components/flight-filters-bar.d.ts.map +1 -1
  19. package/dist/components/flight-filters-bar.js +21 -13
  20. package/dist/components/flight-itinerary.d.ts.map +1 -1
  21. package/dist/components/flight-itinerary.js +26 -6
  22. package/dist/components/flight-offer-detail.d.ts.map +1 -1
  23. package/dist/components/flight-offer-detail.js +23 -35
  24. package/dist/components/flight-offer-row.d.ts.map +1 -1
  25. package/dist/components/flight-offer-row.js +19 -15
  26. package/dist/components/flight-order-confirmation.d.ts.map +1 -1
  27. package/dist/components/flight-order-confirmation.js +20 -24
  28. package/dist/components/flight-passenger-form.d.ts.map +1 -1
  29. package/dist/components/flight-passenger-form.js +18 -14
  30. package/dist/components/flight-payment-selector.d.ts.map +1 -1
  31. package/dist/components/flight-payment-selector.js +4 -8
  32. package/dist/components/flight-payment-step.d.ts.map +1 -1
  33. package/dist/components/flight-payment-step.js +14 -15
  34. package/dist/components/flight-search-form.d.ts.map +1 -1
  35. package/dist/components/flight-search-form.js +4 -2
  36. package/dist/components/flight-seat-map.d.ts.map +1 -1
  37. package/dist/components/flight-seat-map.js +24 -19
  38. package/dist/components/flight-seats-step.js +26 -24
  39. package/dist/components/flight-services-step.d.ts.map +1 -1
  40. package/dist/components/flight-services-step.js +29 -16
  41. package/dist/components/pax-cabin-popover.d.ts.map +1 -1
  42. package/dist/components/pax-cabin-popover.js +8 -11
  43. package/dist/components/popular-routes.d.ts +0 -5
  44. package/dist/components/popular-routes.d.ts.map +1 -1
  45. package/dist/components/popular-routes.js +25 -43
  46. package/dist/i18n/en.d.ts +404 -0
  47. package/dist/i18n/en.d.ts.map +1 -1
  48. package/dist/i18n/en.js +460 -0
  49. package/dist/i18n/messages.d.ts +331 -0
  50. package/dist/i18n/messages.d.ts.map +1 -1
  51. package/dist/i18n/provider.d.ts +808 -0
  52. package/dist/i18n/provider.d.ts.map +1 -1
  53. package/dist/i18n/ro.d.ts +404 -0
  54. package/dist/i18n/ro.d.ts.map +1 -1
  55. package/dist/i18n/ro.js +460 -0
  56. package/package.json +15 -15
@@ -3,6 +3,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import { PaymentStep, } from "@voyantjs/checkout-ui";
4
4
  import { Landmark } from "lucide-react";
5
5
  import { useMemo } from "react";
6
+ import { useFlightsUiMessagesOrDefault } from "../i18n/index.js";
6
7
  /**
7
8
  * Flight-vertical wrapper around `<PaymentStep>` from `@voyantjs/checkout-ui`.
8
9
  * Maps the universal `PaymentChoice` event into the flight contract's
@@ -10,7 +11,15 @@ import { useMemo } from "react";
10
11
  * credit" extra option (flight-specific).
11
12
  */
12
13
  export function FlightPaymentStep({ value, onChange, savedMethods, loadingSavedMethods, selectedSavedId, onSelectSaved, capabilities, }) {
13
- const choice = useMemo(() => intentToChoice(value, savedMethods, selectedSavedId), [value, savedMethods, selectedSavedId]);
14
+ const messages = useFlightsUiMessagesOrDefault().flightPaymentStep;
15
+ const extraAgencyCredit = useMemo(() => ({
16
+ id: "ticket_on_credit",
17
+ label: messages.agencyCreditLabel,
18
+ description: messages.agencyCreditDescription,
19
+ icon: _jsx(Landmark, { className: "h-4 w-4 text-muted-foreground" }),
20
+ }), [messages]);
21
+ const extraOptions = useMemo(() => [extraAgencyCredit], [extraAgencyCredit]);
22
+ const choice = useMemo(() => intentToChoice(value, savedMethods, selectedSavedId, extraAgencyCredit.id), [value, savedMethods, selectedSavedId, extraAgencyCredit.id]);
14
23
  return (_jsx(PaymentStep, { value: choice, onChange: (next) => {
15
24
  if (!next) {
16
25
  onChange({ type: "hold" });
@@ -40,31 +49,21 @@ export function FlightPaymentStep({ value, onChange, savedMethods, loadingSavedM
40
49
  });
41
50
  return;
42
51
  }
43
- if (next.type === "extra" && next.optionId === EXTRA_AGENCY_CREDIT.id) {
52
+ if (next.type === "extra" && next.optionId === extraAgencyCredit.id) {
44
53
  onChange({ type: "ticket_on_credit" });
45
54
  return;
46
55
  }
47
56
  // `hold` at the contract level — the parent's order-creation flow
48
57
  // produces a payment session + landing URL the operator shares.
49
58
  onChange({ type: "hold" });
50
- }, capabilities: capabilities ?? {}, savedMethods: savedMethods, loadingSavedMethods: loadingSavedMethods, extraOptions: FLIGHT_EXTRA_OPTIONS }));
59
+ }, capabilities: capabilities ?? {}, savedMethods: savedMethods, loadingSavedMethods: loadingSavedMethods, extraOptions: extraOptions }));
51
60
  }
52
61
  // ─────────────────────────────────────────────────────────────────────────────
53
- // Flight-specific extras
54
- // ─────────────────────────────────────────────────────────────────────────────
55
- const EXTRA_AGENCY_CREDIT = {
56
- id: "ticket_on_credit",
57
- label: "Issue ticket on agency credit",
58
- description: "Bill against the agency's IATA / consolidator credit line.",
59
- icon: _jsx(Landmark, { className: "h-4 w-4 text-muted-foreground" }),
60
- };
61
- const FLIGHT_EXTRA_OPTIONS = [EXTRA_AGENCY_CREDIT];
62
- // ─────────────────────────────────────────────────────────────────────────────
63
62
  // PaymentIntent ⇄ PaymentChoice translation
64
63
  // ─────────────────────────────────────────────────────────────────────────────
65
- function intentToChoice(intent, savedMethods, selectedSavedId) {
64
+ function intentToChoice(intent, savedMethods, selectedSavedId, agencyCreditOptionId) {
66
65
  if (intent.type === "ticket_on_credit") {
67
- return { type: "extra", optionId: EXTRA_AGENCY_CREDIT.id };
66
+ return { type: "extra", optionId: agencyCreditOptionId };
68
67
  }
69
68
  if (intent.type === "card") {
70
69
  if (selectedSavedId) {
@@ -1 +1 @@
1
- {"version":3,"file":"flight-search-form.d.ts","sourceRoot":"","sources":["../../src/components/flight-search-form.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,mBAAmB,EAGpB,MAAM,kCAAkC,CAAA;AAUzC,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAA;AAE/C,MAAM,WAAW,qBAAqB;IACpC,sDAAsD;IACtD,QAAQ,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAA;IAChD,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG;QAAE,QAAQ,CAAC,EAAE,QAAQ,CAAA;KAAE,CAAA;CACjE;AAED,wBAAgB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,qBAAqB,2CAmIrF"}
1
+ {"version":3,"file":"flight-search-form.d.ts","sourceRoot":"","sources":["../../src/components/flight-search-form.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,mBAAmB,EAGpB,MAAM,kCAAkC,CAAA;AAUzC,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAA;AAE/C,MAAM,WAAW,qBAAqB;IACpC,sDAAsD;IACtD,QAAQ,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAA;IAChD,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG;QAAE,QAAQ,CAAC,EAAE,QAAQ,CAAA;KAAE,CAAA;CACjE;AAED,wBAAgB,gBAAgB,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,qBAAqB,2CAoIrF"}
@@ -5,9 +5,11 @@ import { DatePicker } from "@voyantjs/ui/components/date-picker";
5
5
  import { ToggleGroup, ToggleGroupItem } from "@voyantjs/ui/components/toggle-group";
6
6
  import { ArrowLeftRight, Search } from "lucide-react";
7
7
  import { useState } from "react";
8
+ import { useFlightsUiMessagesOrDefault } from "../i18n/index.js";
8
9
  import { AirportCombobox } from "./airport-combobox.js";
9
10
  import { PaxCabinPopover } from "./pax-cabin-popover.js";
10
11
  export function FlightSearchForm({ onSearch, loading, initial }) {
12
+ const messages = useFlightsUiMessagesOrDefault().flightSearchForm;
11
13
  const initialSlices = initial?.slices ?? [];
12
14
  const [tripType, setTripType] = useState(initial?.tripType ?? (initialSlices.length === 2 ? "round_trip" : "one_way"));
13
15
  const [origin, setOrigin] = useState(initialSlices[0]?.origin ?? null);
@@ -49,8 +51,8 @@ export function FlightSearchForm({ onSearch, loading, initial }) {
49
51
  const next = v[0];
50
52
  if (next)
51
53
  setTripType(next);
52
- }, children: [_jsx(ToggleGroupItem, { size: "lg", value: "round_trip", children: "Round-trip" }), _jsx(ToggleGroupItem, { size: "lg", value: "one_way", children: "One-way" })] }), _jsxs("div", { className: "flex flex-1 items-center gap-1", children: [_jsx(AirportCombobox, { value: origin, onChange: setOrigin, placeholder: "From", className: "flex-1" }), _jsx(Button, { type: "button", variant: "outline", size: "icon", onClick: swap, "aria-label": "Swap origin and destination", className: "size-10 shrink-0", children: _jsx(ArrowLeftRight, { className: "h-4 w-4" }) }), _jsx(AirportCombobox, { value: destination, onChange: setDestination, placeholder: "To", className: "flex-1" })] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx(DatePicker, { value: departureDate, onChange: setDepartureDate, placeholder: "Depart", className: "h-10 flex-1 min-w-32" }), _jsx(DatePicker, { value: returnDate, onChange: setReturnDate, placeholder: "Return", disabled: tripType === "one_way", className: "h-10 flex-1 min-w-32" })] }), _jsx(PaxCabinPopover, { passengers: passengers, cabin: cabin, onChange: (next) => {
54
+ }, children: [_jsx(ToggleGroupItem, { size: "lg", value: "round_trip", children: messages.roundTrip }), _jsx(ToggleGroupItem, { size: "lg", value: "one_way", children: messages.oneWay })] }), _jsxs("div", { className: "flex flex-1 items-center gap-1", children: [_jsx(AirportCombobox, { value: origin, onChange: setOrigin, placeholder: messages.fromPlaceholder, className: "flex-1" }), _jsx(Button, { type: "button", variant: "outline", size: "icon", onClick: swap, "aria-label": messages.swapAriaLabel, className: "size-10 shrink-0", children: _jsx(ArrowLeftRight, { className: "h-4 w-4" }) }), _jsx(AirportCombobox, { value: destination, onChange: setDestination, placeholder: messages.toPlaceholder, className: "flex-1" })] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx(DatePicker, { value: departureDate, onChange: setDepartureDate, placeholder: messages.departPlaceholder, className: "h-10 flex-1 min-w-32" }), _jsx(DatePicker, { value: returnDate, onChange: setReturnDate, placeholder: messages.returnPlaceholder, disabled: tripType === "one_way", className: "h-10 flex-1 min-w-32" })] }), _jsx(PaxCabinPopover, { passengers: passengers, cabin: cabin, onChange: (next) => {
53
55
  setPassengers(next.passengers);
54
56
  setCabin(next.cabin);
55
- } }), _jsxs(Button, { type: "submit", size: "lg", disabled: !ready || loading, className: "shrink-0 px-6", children: [_jsx(Search, { className: "mr-2 h-4 w-4" }), loading ? "Searching…" : "Search"] })] }) }));
57
+ } }), _jsxs(Button, { type: "submit", size: "lg", disabled: !ready || loading, className: "shrink-0 px-6", children: [_jsx(Search, { className: "mr-2 h-4 w-4" }), loading ? messages.searching : messages.search] })] }) }));
56
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"flight-seat-map.d.ts","sourceRoot":"","sources":["../../src/components/flight-seat-map.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAA;AAUrE;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAA;IACb,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAA;IAChB,4EAA4E;IAC5E,KAAK,EAAE,cAAc,EAAE,CAAA;IACvB,mFAAmF;IACnF,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAClC,yEAAyE;IACzE,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,KAAK,EACL,WAAW,EACX,mBAAmB,EACnB,SAAS,GACV,EAAE,kBAAkB,2CA0BpB"}
1
+ {"version":3,"file":"flight-seat-map.d.ts","sourceRoot":"","sources":["../../src/components/flight-seat-map.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAA;AAYrE;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAA;IACb,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAA;IAChB,4EAA4E;IAC5E,KAAK,EAAE,cAAc,EAAE,CAAA;IACvB,mFAAmF;IACnF,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAClC,yEAAyE;IACzE,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,KAAK,EACL,WAAW,EACX,mBAAmB,EACnB,SAAS,GACV,EAAE,kBAAkB,2CA6BpB"}
@@ -1,8 +1,10 @@
1
1
  "use client";
2
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { formatMessage } from "@voyantjs/i18n";
3
4
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@voyantjs/ui/components/tooltip";
4
5
  import { cn } from "@voyantjs/ui/lib/utils";
5
6
  import { Plane } from "lucide-react";
7
+ import { useFlightsUiMessagesOrDefault } from "../i18n/index.js";
6
8
  /**
7
9
  * Visual seat map. Renders each row of the aircraft using the supplied
8
10
  * `columnLayout` (with `null` slots becoming aisles), each seat as a
@@ -12,19 +14,22 @@ import { Plane } from "lucide-react";
12
14
  * Pure presentational — state lives in the parent step.
13
15
  */
14
16
  export function FlightSeatMap({ seatMap, picks, onSeatClick, highlightedPaxLabel, className, }) {
17
+ const messages = useFlightsUiMessagesOrDefault();
15
18
  const aircraftName = seatMap.providerData?.aircraftName ?? seatMap.aircraft;
16
- return (_jsx(TooltipProvider, { delay: 200, children: _jsxs("div", { className: cn("flex flex-col items-center gap-3", className), children: [_jsxs("div", { className: "flex items-center gap-2 text-muted-foreground text-xs", children: [_jsx(Plane, { className: "h-3.5 w-3.5" }), aircraftName ?? "Cabin", highlightedPaxLabel && (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-foreground/60", children: "\u00B7" }), _jsxs("span", { className: "text-foreground", children: ["Picking seat for ", _jsx("span", { className: "font-medium", children: highlightedPaxLabel })] })] }))] }), _jsx("div", { className: "rounded-2xl border bg-card p-4", children: _jsx(Cabin, { seatMap: seatMap, picks: picks, onSeatClick: onSeatClick }) }), _jsx(Legend, {})] }) }));
19
+ return (_jsx(TooltipProvider, { delay: 200, children: _jsxs("div", { className: cn("flex flex-col items-center gap-3", className), children: [_jsxs("div", { className: "flex items-center gap-2 text-muted-foreground text-xs", children: [_jsx(Plane, { className: "h-3.5 w-3.5" }), aircraftName ?? messages.flightSeatMap.cabin, highlightedPaxLabel && (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-foreground/60", children: "\u00B7" }), _jsx("span", { className: "text-foreground", children: formatMessage(messages.flightSeatMap.pickingSeatFor, {
20
+ passenger: highlightedPaxLabel,
21
+ }) })] }))] }), _jsx("div", { className: "rounded-2xl border bg-card p-4", children: _jsx(Cabin, { seatMap: seatMap, picks: picks, onSeatClick: onSeatClick, messages: messages }) }), _jsx(Legend, { messages: messages })] }) }));
17
22
  }
18
23
  // ─────────────────────────────────────────────────────────────────────────────
19
- function Cabin({ seatMap, picks, onSeatClick, }) {
24
+ function Cabin({ seatMap, picks, onSeatClick, messages, }) {
20
25
  const layout = seatMap.columnLayout;
21
26
  const pickIndex = new Map(picks.map((p) => [p.seatNumber, p]));
22
- return (_jsxs("div", { className: "flex flex-col items-center gap-1", children: [_jsx(ColumnHeader, { layout: layout }), seatMap.rows.map((row) => (_jsx(SeatRowView, { rowNumber: row.row, layout: layout, seats: row.seats, pickIndex: pickIndex, onSeatClick: onSeatClick }, row.row)))] }));
27
+ return (_jsxs("div", { className: "flex flex-col items-center gap-1", children: [_jsx(ColumnHeader, { layout: layout }), seatMap.rows.map((row) => (_jsx(SeatRowView, { rowNumber: row.row, layout: layout, seats: row.seats, pickIndex: pickIndex, onSeatClick: onSeatClick, messages: messages }, row.row)))] }));
23
28
  }
24
29
  function ColumnHeader({ layout }) {
25
30
  return (_jsxs("div", { className: "mb-1 flex items-center gap-1", children: [_jsx("span", { className: "w-6 shrink-0 text-center font-mono text-[10px] text-muted-foreground" }), layout.map((col, i) => col == null ? (_jsx("div", { className: "w-3 shrink-0" }, `gap-${i}`)) : (_jsx("span", { className: "w-7 shrink-0 text-center font-mono text-[10px] text-muted-foreground", children: col }, `col-${i}`)))] }));
26
31
  }
27
- function SeatRowView({ rowNumber, layout, seats, pickIndex, onSeatClick, }) {
32
+ function SeatRowView({ rowNumber, layout, seats, pickIndex, onSeatClick, messages, }) {
28
33
  const seatByCol = new Map(seats.map((s) => [s.column, s]));
29
34
  return (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("span", { className: "w-6 shrink-0 text-center font-mono text-[10px] text-muted-foreground tabular-nums", children: rowNumber }), layout.map((col, i) => {
30
35
  if (col == null) {
@@ -34,21 +39,21 @@ function SeatRowView({ rowNumber, layout, seats, pickIndex, onSeatClick, }) {
34
39
  if (!seat) {
35
40
  return (_jsx("div", { className: "h-7 w-7 shrink-0 rounded-md border border-dashed border-muted/30" }, `gap-${rowNumber}-${i}`));
36
41
  }
37
- return (_jsx(SeatTile, { seat: seat, pick: pickIndex.get(seat.seatNumber) ?? null, onClick: onSeatClick }, seat.seatNumber));
42
+ return (_jsx(SeatTile, { seat: seat, pick: pickIndex.get(seat.seatNumber) ?? null, onClick: onSeatClick, messages: messages }, seat.seatNumber));
38
43
  })] }));
39
44
  }
40
- function SeatTile({ seat, pick, onClick, }) {
45
+ function SeatTile({ seat, pick, onClick, messages, }) {
41
46
  const isClickable = !!onClick && (seat.status === "available" || seat.status === "selected" || pick != null);
42
47
  const tile = (_jsxs("button", { type: "button", disabled: !isClickable, onClick: onClick ? () => onClick(seat) : undefined, className: cn("relative flex h-7 w-7 shrink-0 items-center justify-center rounded-md border font-mono text-[10px] transition-colors", seat.status === "available" && categoryClasses(seat.category), seat.status === "blocked" && "cursor-not-allowed border-transparent bg-muted/60", seat.status === "unavailable" && "cursor-not-allowed border-transparent bg-muted/30", pick && (pick.swatch ?? "bg-primary text-primary-foreground border-primary"), isClickable && !pick && "hover:border-primary hover:bg-primary/5"), children: [pick ? _jsx("span", { className: "font-semibold", children: pick.label }) : null, seat.category === "exit_row" && !pick && (_jsx("span", { className: "absolute top-0 right-0 text-[7px] font-bold leading-none text-amber-600", children: "E" }))] }));
43
48
  if (!isClickable && seat.status !== "available")
44
49
  return tile;
45
- return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { render: tile }), _jsx(TooltipContent, { className: "max-w-[220px]", children: _jsx(SeatTooltip, { seat: seat, pickedBy: pick?.label }) })] }));
50
+ return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { render: tile }), _jsx(TooltipContent, { className: "max-w-[220px]", children: _jsx(SeatTooltip, { seat: seat, pickedBy: pick?.label, messages: messages }) })] }));
46
51
  }
47
- function SeatTooltip({ seat, pickedBy }) {
48
- return (_jsxs("div", { className: "flex flex-col gap-1 text-xs", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "font-mono font-semibold", children: seat.seatNumber }), _jsxs("span", { className: "text-muted-foreground", children: [humanCategory(seat.category), seat.window && " · window", seat.aisle && " · aisle"] })] }), seat.price ? (_jsxs("span", { className: "font-medium", children: ["+", formatMoney(seat.price.amount, seat.price.currency)] })) : (_jsx("span", { className: "text-muted-foreground", children: "No charge" })), seat.notes && _jsx("span", { className: "text-muted-foreground", children: seat.notes }), pickedBy && _jsxs("span", { className: "text-primary", children: ["Picked by ", pickedBy] })] }));
52
+ function SeatTooltip({ seat, pickedBy, messages, }) {
53
+ return (_jsxs("div", { className: "flex flex-col gap-1 text-xs", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "font-mono font-semibold", children: seat.seatNumber }), _jsxs("span", { className: "text-muted-foreground", children: [humanCategory(seat.category, messages), seat.window && ` · ${messages.flightSeatMap.window}`, seat.aisle && ` · ${messages.flightSeatMap.aisle}`] })] }), seat.price ? (_jsxs("span", { className: "font-medium", children: ["+", formatMoney(seat.price.amount, seat.price.currency)] })) : (_jsx("span", { className: "text-muted-foreground", children: messages.flightSeatMap.noCharge })), seat.notes && _jsx("span", { className: "text-muted-foreground", children: seat.notes }), pickedBy && (_jsx("span", { className: "text-primary", children: formatMessage(messages.flightSeatMap.pickedBy, { passenger: pickedBy }) }))] }));
49
54
  }
50
- function Legend() {
51
- return (_jsxs("div", { className: "flex flex-wrap items-center justify-center gap-3 text-[11px] text-muted-foreground", children: [_jsx(LegendChip, { className: "border-emerald-500/60 bg-card", label: "Available" }), _jsx(LegendChip, { className: "border-cyan-500/60 bg-cyan-500/5", label: "Preferred" }), _jsx(LegendChip, { className: "border-amber-500/60 bg-amber-500/5", label: "Exit row" }), _jsx(LegendChip, { className: "bg-primary text-primary-foreground", label: "Picked" }), _jsx(LegendChip, { className: "bg-muted/60", label: "Taken" })] }));
55
+ function Legend({ messages }) {
56
+ return (_jsxs("div", { className: "flex flex-wrap items-center justify-center gap-3 text-[11px] text-muted-foreground", children: [_jsx(LegendChip, { className: "border-emerald-500/60 bg-card", label: messages.flightSeatMap.legend.available }), _jsx(LegendChip, { className: "border-cyan-500/60 bg-cyan-500/5", label: messages.flightSeatMap.legend.preferred }), _jsx(LegendChip, { className: "border-amber-500/60 bg-amber-500/5", label: messages.flightSeatMap.legend.exitRow }), _jsx(LegendChip, { className: "bg-primary text-primary-foreground", label: messages.flightSeatMap.legend.picked }), _jsx(LegendChip, { className: "bg-muted/60", label: messages.flightSeatMap.legend.taken })] }));
52
57
  }
53
58
  function LegendChip({ className, label }) {
54
59
  return (_jsxs("span", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: cn("h-3.5 w-3.5 rounded-sm border", className) }), label] }));
@@ -68,20 +73,20 @@ function categoryClasses(category) {
68
73
  return "border-emerald-500/60 bg-card text-emerald-700";
69
74
  }
70
75
  }
71
- function humanCategory(c) {
76
+ function humanCategory(c, messages) {
72
77
  switch (c) {
73
78
  case "exit_row":
74
- return "Exit row · extra legroom";
79
+ return messages.flightSeatMap.categories.exit_row;
75
80
  case "extra_legroom":
76
- return "Extra legroom";
81
+ return messages.flightSeatMap.categories.extra_legroom;
77
82
  case "preferred":
78
- return "Preferred";
83
+ return messages.flightSeatMap.categories.preferred;
79
84
  case "premium":
80
- return "Premium";
85
+ return messages.flightSeatMap.categories.premium;
81
86
  case "bulkhead":
82
- return "Bulkhead";
87
+ return messages.flightSeatMap.categories.bulkhead;
83
88
  default:
84
- return "Standard";
89
+ return messages.flightSeatMap.categories.standard;
85
90
  }
86
91
  }
87
92
  function formatMoney(amount, currency) {
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import { cn } from "@voyantjs/ui/lib/utils";
4
4
  import { CheckCircle2, X } from "lucide-react";
5
5
  import { useEffect, useMemo, useState } from "react";
6
+ import { useFlightsUiMessagesOrDefault } from "../i18n/index.js";
6
7
  import { FlightSeatMap } from "./flight-seat-map.js";
7
8
  /**
8
9
  * Wizz-style seat selection step. Tri-option gate up top (Skip / Auto-assign
@@ -12,8 +13,9 @@ import { FlightSeatMap } from "./flight-seat-map.js";
12
13
  * seat assigns it to the active passenger and moves the cursor on.
13
14
  */
14
15
  export function FlightSeatsStep({ outboundOffer, returnOffer, passengers, passengerCounts, getSeatMap, value, onChange, mode, onModeChange, }) {
15
- const segments = useMemo(() => collectSegments(outboundOffer, returnOffer), [outboundOffer, returnOffer]);
16
- const paxRows = useMemo(() => buildPassengerRows(passengers, passengerCounts), [passengers, passengerCounts]);
16
+ const messages = useFlightsUiMessagesOrDefault();
17
+ const segments = useMemo(() => collectSegments(outboundOffer, returnOffer, messages), [outboundOffer, returnOffer, messages]);
18
+ const paxRows = useMemo(() => buildPassengerRows(passengers, passengerCounts, messages), [passengers, passengerCounts, messages]);
17
19
  const [activeSegmentIdx, setActiveSegmentIdx] = useState(0);
18
20
  const [activePaxIdx, setActivePaxIdx] = useState(0);
19
21
  // Auto-advance to the next pax once a seat is picked for the current one.
@@ -34,7 +36,7 @@ export function FlightSeatsStep({ outboundOffer, returnOffer, passengers, passen
34
36
  }
35
37
  }, [value, segments, activeSegmentIdx, paxRows, mode]);
36
38
  const activeSegment = segments[activeSegmentIdx] ?? null;
37
- return (_jsxs("div", { className: "flex flex-col gap-5", children: [_jsxs("div", { children: [_jsx("h2", { className: "font-semibold text-base", children: "Choose your seats" }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Sit where you want, or let the airline assign seats at check-in." })] }), _jsx(ModePicker, { mode: mode, onChange: onModeChange }), mode === "now" && activeSegment && (_jsxs("div", { className: "flex flex-col gap-4", children: [_jsx(SegmentTabs, { segments: segments, activeIdx: activeSegmentIdx, paxCount: paxRows.length, picks: value, onChange: (idx) => {
39
+ return (_jsxs("div", { className: "flex flex-col gap-5", children: [_jsxs("div", { children: [_jsx("h2", { className: "font-semibold text-base", children: messages.flightSeatsStep.title }), _jsx("p", { className: "text-muted-foreground text-sm", children: messages.flightSeatsStep.description })] }), _jsx(ModePicker, { mode: mode, onChange: onModeChange, messages: messages }), mode === "now" && activeSegment && (_jsxs("div", { className: "flex flex-col gap-4", children: [_jsx(SegmentTabs, { segments: segments, activeIdx: activeSegmentIdx, paxCount: paxRows.length, picks: value, onChange: (idx) => {
38
40
  setActiveSegmentIdx(idx);
39
41
  setActivePaxIdx(0);
40
42
  } }), _jsx(PaxBar, { paxRows: paxRows, activeIdx: activePaxIdx, picks: value, segmentId: activeSegment.segmentId, onActivate: setActivePaxIdx, onClear: (passengerId) => {
@@ -42,7 +44,7 @@ export function FlightSeatsStep({ outboundOffer, returnOffer, passengers, passen
42
44
  } }), _jsx(SeatMapPanel, { slot: getSeatMap({
43
45
  offerId: activeSegment.offerId,
44
46
  segmentId: activeSegment.segmentId,
45
- }), paxRows: paxRows, activePaxIdx: activePaxIdx, picks: value, segmentId: activeSegment.segmentId, onPick: (seat) => {
47
+ }), paxRows: paxRows, activePaxIdx: activePaxIdx, picks: value, segmentId: activeSegment.segmentId, messages: messages, onPick: (seat) => {
46
48
  const pax = paxRows[activePaxIdx];
47
49
  if (!pax)
48
50
  return;
@@ -65,11 +67,11 @@ const PAX_SWATCHES = [
65
67
  "bg-teal-600 text-white border-teal-700",
66
68
  "bg-indigo-600 text-white border-indigo-700",
67
69
  ];
68
- function ModePicker({ mode, onChange }) {
69
- return (_jsxs("div", { className: "grid gap-2 md:grid-cols-3", children: [_jsx(ModeCard, { active: mode === "skip", onClick: () => onChange("skip"), title: "Pick seats later", body: "Seats will be assigned automatically at check-in. May not be next to each other." }), _jsx(ModeCard, { active: mode === "auto", onClick: () => onChange("auto"), title: "Auto-assign together", body: "Airline picks seats trying to keep your party together. No fee.", recommended: true }), _jsx(ModeCard, { active: mode === "now", onClick: () => onChange("now"), title: "Choose seats now", body: "Pick exact seats per leg \u2014 windows, exit rows, extra legroom." })] }));
70
+ function ModePicker({ mode, onChange, messages, }) {
71
+ return (_jsxs("div", { className: "grid gap-2 md:grid-cols-3", children: [_jsx(ModeCard, { active: mode === "skip", onClick: () => onChange("skip"), title: messages.flightSeatsStep.modes.skip.title, body: messages.flightSeatsStep.modes.skip.body }), _jsx(ModeCard, { active: mode === "auto", onClick: () => onChange("auto"), title: messages.flightSeatsStep.modes.auto.title, body: messages.flightSeatsStep.modes.auto.body, recommended: true, messages: messages }), _jsx(ModeCard, { active: mode === "now", onClick: () => onChange("now"), title: messages.flightSeatsStep.modes.now.title, body: messages.flightSeatsStep.modes.now.body })] }));
70
72
  }
71
- function ModeCard({ active, onClick, title, body, recommended, }) {
72
- return (_jsxs("button", { type: "button", onClick: onClick, className: cn("relative flex flex-col items-start gap-1 rounded-lg border bg-card p-4 text-left transition-colors", active ? "border-primary ring-2 ring-primary/20" : "hover:border-primary/40"), children: [recommended && (_jsx("span", { className: "absolute top-2 right-2 rounded-full bg-primary/10 px-2 py-0.5 font-medium text-[9px] text-primary uppercase tracking-wider", children: "Recommended" })), active && _jsx(CheckCircle2, { className: "absolute top-3 right-3 h-4 w-4 text-primary" }), _jsx("span", { className: "font-medium text-sm", children: title }), _jsx("span", { className: "text-muted-foreground text-xs", children: body })] }));
73
+ function ModeCard({ active, onClick, title, body, recommended, messages, }) {
74
+ return (_jsxs("button", { type: "button", onClick: onClick, className: cn("relative flex flex-col items-start gap-1 rounded-lg border bg-card p-4 text-left transition-colors", active ? "border-primary ring-2 ring-primary/20" : "hover:border-primary/40"), children: [recommended && (_jsx("span", { className: "absolute top-2 right-2 rounded-full bg-primary/10 px-2 py-0.5 font-medium text-[9px] text-primary uppercase tracking-wider", children: messages?.common.recommended })), active && _jsx(CheckCircle2, { className: "absolute top-3 right-3 h-4 w-4 text-primary" }), _jsx("span", { className: "font-medium text-sm", children: title }), _jsx("span", { className: "text-muted-foreground text-xs", children: body })] }));
73
75
  }
74
76
  function SegmentTabs({ segments, activeIdx, paxCount, picks, onChange, }) {
75
77
  return (_jsx("div", { className: "flex items-center gap-2 overflow-x-auto rounded-md border bg-muted/20 p-1", children: segments.map((seg, idx) => {
@@ -89,7 +91,7 @@ function PaxBar({ paxRows, activeIdx, picks, segmentId, onActivate, onClear, })
89
91
  } })] })) : (_jsx("span", { className: "text-muted-foreground", children: "\u2014" }))] }) }, pax.passengerId));
90
92
  }) }));
91
93
  }
92
- function SeatMapPanel({ slot, paxRows, activePaxIdx, picks, segmentId, onPick, }) {
94
+ function SeatMapPanel({ slot, paxRows, activePaxIdx, picks, segmentId, onPick, messages, }) {
93
95
  if (slot.loading) {
94
96
  return _jsx("div", { className: "h-72 animate-pulse rounded-2xl bg-muted/40" });
95
97
  }
@@ -97,7 +99,7 @@ function SeatMapPanel({ slot, paxRows, activePaxIdx, picks, segmentId, onPick, }
97
99
  return (_jsx("div", { className: "rounded-xl border border-destructive/40 bg-destructive/5 p-4 text-destructive text-sm", children: slot.error }));
98
100
  }
99
101
  if (!slot.seatMap) {
100
- return (_jsx("div", { className: "rounded-xl border border-dashed p-6 text-center text-muted-foreground text-sm", children: "Seat map unavailable for this segment." }));
102
+ return (_jsx("div", { className: "rounded-xl border border-dashed p-6 text-center text-muted-foreground text-sm", children: messages.flightSeatsStep.seatMapUnavailable }));
101
103
  }
102
104
  const markers = picks
103
105
  .filter((p) => p.segmentId === segmentId)
@@ -118,13 +120,13 @@ function SeatMapPanel({ slot, paxRows, activePaxIdx, picks, segmentId, onPick, }
118
120
  // ─────────────────────────────────────────────────────────────────────────────
119
121
  // Helpers
120
122
  // ─────────────────────────────────────────────────────────────────────────────
121
- function collectSegments(outbound, returnLeg) {
123
+ function collectSegments(outbound, returnLeg, messages) {
122
124
  const out = [];
123
125
  for (const seg of itinerarySegments(outbound)) {
124
126
  out.push({
125
127
  offerId: outbound.offerId,
126
128
  segmentId: seg.segmentId,
127
- legLabel: "Outbound",
129
+ legLabel: messages.common.legLabels.outbound,
128
130
  origin: seg.departure.iataCode,
129
131
  destination: seg.arrival.iataCode,
130
132
  carrier: seg.carrierCode,
@@ -136,7 +138,7 @@ function collectSegments(outbound, returnLeg) {
136
138
  out.push({
137
139
  offerId: returnLeg.offerId,
138
140
  segmentId: seg.segmentId,
139
- legLabel: "Return",
141
+ legLabel: messages.common.legLabels.return,
140
142
  origin: seg.departure.iataCode,
141
143
  destination: seg.arrival.iataCode,
142
144
  carrier: seg.carrierCode,
@@ -154,7 +156,7 @@ function itinerarySegments(offer) {
154
156
  }
155
157
  return out;
156
158
  }
157
- function buildPassengerRows(passengers, counts) {
159
+ function buildPassengerRows(passengers, counts, messages) {
158
160
  const rows = [];
159
161
  const total = passengers.length > 0
160
162
  ? passengers.length
@@ -164,7 +166,7 @@ function buildPassengerRows(passengers, counts) {
164
166
  if (p) {
165
167
  rows.push({
166
168
  passengerId: p.passengerId,
167
- label: nameOrFallback(p, i),
169
+ label: nameOrFallback(p, i, messages),
168
170
  short: shortLabel(p, i),
169
171
  swatch: PAX_SWATCHES[i % PAX_SWATCHES.length] ?? PAX_SWATCHES[0],
170
172
  });
@@ -172,7 +174,7 @@ function buildPassengerRows(passengers, counts) {
172
174
  else {
173
175
  rows.push({
174
176
  passengerId: synthPaxId(i, counts),
175
- label: synthPaxLabel(i, counts),
177
+ label: synthPaxLabel(i, counts, messages),
176
178
  short: String(i + 1),
177
179
  swatch: PAX_SWATCHES[i % PAX_SWATCHES.length] ?? PAX_SWATCHES[0],
178
180
  });
@@ -180,12 +182,11 @@ function buildPassengerRows(passengers, counts) {
180
182
  }
181
183
  return rows;
182
184
  }
183
- function nameOrFallback(p, idx) {
185
+ function nameOrFallback(p, idx, messages) {
184
186
  const full = `${p.firstName} ${p.lastName}`.trim();
185
187
  if (full)
186
188
  return full;
187
- const cap = p.type[0]?.toUpperCase() + p.type.slice(1);
188
- return `${cap} ${idx + 1}`;
189
+ return `${messages.common.passengerTypeLabels[p.type]} ${idx + 1}`;
189
190
  }
190
191
  function shortLabel(p, idx) {
191
192
  const initials = `${p.firstName[0] ?? ""}${p.lastName[0] ?? ""}`.trim();
@@ -201,11 +202,12 @@ function synthPaxId(i, counts) {
201
202
  return `pax_child_${afterAdults + 1}`;
202
203
  return `pax_infant_${i - counts.adults - (counts.children ?? 0) + 1}`;
203
204
  }
204
- function synthPaxLabel(i, counts) {
205
+ function synthPaxLabel(i, counts, messages) {
205
206
  if (i < counts.adults)
206
- return `Adult ${i + 1}`;
207
+ return `${messages.common.passengerTypeLabels.adult} ${i + 1}`;
207
208
  const afterAdults = i - counts.adults;
208
- if (afterAdults < (counts.children ?? 0))
209
- return `Child ${afterAdults + 1}`;
210
- return `Infant ${i - counts.adults - (counts.children ?? 0) + 1}`;
209
+ if (afterAdults < (counts.children ?? 0)) {
210
+ return `${messages.common.passengerTypeLabels.child} ${afterAdults + 1}`;
211
+ }
212
+ return `${messages.common.passengerTypeLabels.infant} ${i - counts.adults - (counts.children ?? 0) + 1}`;
211
213
  }
@@ -1 +1 @@
1
- {"version":3,"file":"flight-services-step.d.ts","sourceRoot":"","sources":["../../src/components/flight-services-step.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,gBAAgB,EAEhB,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,eAAe,EAChB,MAAM,kCAAkC,CAAA;AAOzC,KAAK,eAAe,GAAG,WAAW,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,CAAA;AACpE,KAAK,WAAW,GAAG,WAAW,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAA;AAE5D,MAAM,WAAW,uBAAuB;IACtC,yEAAyE;IACzE,eAAe,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACxC,aAAa,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACvC,aAAa,EAAE,WAAW,CAAA;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,UAAU,EAAE,eAAe,EAAE,CAAA;IAC7B,eAAe,EAAE,eAAe,CAAA;IAChC,UAAU,EAAE,eAAe,CAAA;IAC3B,MAAM,EAAE,WAAW,CAAA;IACnB,kBAAkB,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAA;IACnD,cAAc,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAA;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,eAAe,EACf,aAAa,EACb,aAAa,EACb,WAAW,EACX,UAAU,EACV,eAAe,EACf,UAAU,EACV,MAAM,EACN,kBAAkB,EAClB,cAAc,EACd,OAAO,GACR,EAAE,uBAAuB,2CAyFzB"}
1
+ {"version":3,"file":"flight-services-step.d.ts","sourceRoot":"","sources":["../../src/components/flight-services-step.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,gBAAgB,EAEhB,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,eAAe,EAChB,MAAM,kCAAkC,CAAA;AASzC,KAAK,eAAe,GAAG,WAAW,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,CAAA;AACpE,KAAK,WAAW,GAAG,WAAW,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAA;AAE5D,MAAM,WAAW,uBAAuB;IACtC,yEAAyE;IACzE,eAAe,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACxC,aAAa,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACvC,aAAa,EAAE,WAAW,CAAA;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,UAAU,EAAE,eAAe,EAAE,CAAA;IAC7B,eAAe,EAAE,eAAe,CAAA;IAChC,UAAU,EAAE,eAAe,CAAA;IAC3B,MAAM,EAAE,WAAW,CAAA;IACnB,kBAAkB,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAA;IACnD,cAAc,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAA;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,eAAe,EACf,aAAa,EACb,aAAa,EACb,WAAW,EACX,UAAU,EACV,eAAe,EACf,UAAU,EACV,MAAM,EACN,kBAAkB,EAClB,cAAc,EACd,OAAO,GACR,EAAE,uBAAuB,2CA6FzB"}
@@ -1,10 +1,12 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { formatMessage } from "@voyantjs/i18n";
3
4
  import { Button } from "@voyantjs/ui/components/button";
4
5
  import { Checkbox } from "@voyantjs/ui/components/checkbox";
5
6
  import { cn } from "@voyantjs/ui/lib/utils";
6
7
  import { Accessibility, Minus, Package, Plus, Sparkles } from "lucide-react";
7
8
  import { useMemo } from "react";
9
+ import { useFlightsUiMessagesOrDefault } from "../i18n/index.js";
8
10
  /**
9
11
  * Combined services step covering special assistance (per-pax, trip-wide)
10
12
  * and extras (per-pax, per-leg). Assistance is a flat checkbox list per
@@ -13,13 +15,14 @@ import { useMemo } from "react";
13
15
  * leave the step blank and continue.
14
16
  */
15
17
  export function FlightServicesStep({ outboundCatalog, returnCatalog, outboundOffer, returnOffer, passengers, passengerCounts, assistance, extras, onAssistanceChange, onExtrasChange, loading, }) {
18
+ const messages = useFlightsUiMessagesOrDefault();
16
19
  const isRoundTrip = !!returnOffer;
17
- const paxRows = useMemo(() => buildPassengerRows(passengers, passengerCounts), [passengers, passengerCounts]);
20
+ const paxRows = useMemo(() => buildPassengerRows(passengers, passengerCounts, messages), [passengers, passengerCounts, messages]);
18
21
  if (loading) {
19
22
  return (_jsxs("div", { className: "flex flex-col gap-3", children: [_jsx("div", { className: "h-8 w-48 animate-pulse rounded bg-muted/40" }), _jsx("div", { className: "h-40 animate-pulse rounded-xl bg-muted/40" })] }));
20
23
  }
21
24
  if (!outboundCatalog) {
22
- return (_jsx("div", { className: "rounded-xl border border-dashed p-6 text-center text-muted-foreground text-sm", children: "Services couldn't be loaded for this offer." }));
25
+ return (_jsx("div", { className: "rounded-xl border border-dashed p-6 text-center text-muted-foreground text-sm", children: messages.flightServicesStep.servicesUnavailable }));
23
26
  }
24
27
  const toggleAssistance = (passengerId, optionId, checked) => {
25
28
  const filtered = assistance.filter((p) => !(p.passengerId === passengerId && p.optionId === optionId));
@@ -39,12 +42,14 @@ export function FlightServicesStep({ outboundCatalog, returnCatalog, outboundOff
39
42
  onExtrasChange(filtered);
40
43
  }
41
44
  };
42
- return (_jsxs("div", { className: "flex flex-col gap-5", children: [_jsxs("div", { children: [_jsx("h2", { className: "font-semibold text-base", children: "Services & extras" }), _jsx("p", { className: "text-muted-foreground text-sm", children: "Optional \u2014 leave anything blank to skip." })] }), _jsx(AssistanceSection, { passengers: paxRows, options: outboundCatalog.assistance, value: assistance, onToggle: toggleAssistance }), _jsx(ExtrasSection, { legLabel: "Outbound", offer: outboundOffer, catalog: outboundCatalog, passengers: paxRows, sliceIndex: 0, value: extras, onSetQty: setExtraQty }), isRoundTrip && returnCatalog && returnOffer && (_jsx(ExtrasSection, { legLabel: "Return", offer: returnOffer, catalog: returnCatalog, passengers: paxRows, sliceIndex: 1, value: extras, onSetQty: setExtraQty }))] }));
45
+ return (_jsxs("div", { className: "flex flex-col gap-5", children: [_jsxs("div", { children: [_jsx("h2", { className: "font-semibold text-base", children: messages.flightServicesStep.title }), _jsx("p", { className: "text-muted-foreground text-sm", children: messages.flightServicesStep.description })] }), _jsx(AssistanceSection, { passengers: paxRows, options: outboundCatalog.assistance, value: assistance, onToggle: toggleAssistance, messages: messages }), _jsx(ExtrasSection, { legLabel: messages.common.legLabels.outbound, offer: outboundOffer, catalog: outboundCatalog, passengers: paxRows, sliceIndex: 0, value: extras, onSetQty: setExtraQty, messages: messages }), isRoundTrip && returnCatalog && returnOffer && (_jsx(ExtrasSection, { legLabel: messages.common.legLabels.return, offer: returnOffer, catalog: returnCatalog, passengers: paxRows, sliceIndex: 1, value: extras, onSetQty: setExtraQty, messages: messages }))] }));
43
46
  }
44
- function AssistanceSection({ passengers, options, value, onToggle, }) {
45
- return (_jsxs("section", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [_jsxs("header", { className: "mb-4 flex items-center gap-2", children: [_jsx(Accessibility, { className: "h-4 w-4 text-muted-foreground" }), _jsx("h3", { className: "font-medium text-sm", children: "Special assistance" })] }), _jsx("div", { className: "flex flex-col gap-5", children: passengers.map((pax) => {
47
+ function AssistanceSection({ passengers, options, value, onToggle, messages, }) {
48
+ return (_jsxs("section", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [_jsxs("header", { className: "mb-4 flex items-center gap-2", children: [_jsx(Accessibility, { className: "h-4 w-4 text-muted-foreground" }), _jsx("h3", { className: "font-medium text-sm", children: messages.flightServicesStep.specialAssistance })] }), _jsx("div", { className: "flex flex-col gap-5", children: passengers.map((pax) => {
46
49
  const paxPicks = value.filter((v) => v.passengerId === pax.passengerId);
47
- return (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-baseline justify-between gap-2", children: [_jsx("span", { className: "font-medium text-sm", children: pax.label }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: paxPicks.length === 0 ? "No assistance needed" : `${paxPicks.length} selected` })] }), _jsx("div", { className: "flex flex-wrap gap-2", children: options.map((opt) => {
50
+ return (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("div", { className: "flex items-baseline justify-between gap-2", children: [_jsx("span", { className: "font-medium text-sm", children: pax.label }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: paxPicks.length === 0
51
+ ? messages.flightServicesStep.noAssistanceNeeded
52
+ : `${paxPicks.length} ${messages.common.selected}` })] }), _jsx("div", { className: "flex flex-wrap gap-2", children: options.map((opt) => {
48
53
  const checked = paxPicks.some((p) => p.optionId === opt.id);
49
54
  const id = `svc-${pax.passengerId}-${opt.id}`;
50
55
  return (_jsxs("div", { className: cn("flex items-center gap-2 rounded-md border px-3 py-1.5 text-sm transition-colors", checked
@@ -53,13 +58,13 @@ function AssistanceSection({ passengers, options, value, onToggle, }) {
53
58
  }) })] }, pax.passengerId));
54
59
  }) })] }));
55
60
  }
56
- function ExtrasSection({ legLabel, offer, catalog, passengers, sliceIndex, value, onSetQty, }) {
61
+ function ExtrasSection({ legLabel, offer, catalog, passengers, sliceIndex, value, onSetQty, messages, }) {
57
62
  if (catalog.extras.length === 0)
58
63
  return null;
59
64
  const itin = offer.itineraries[0];
60
65
  const first = itin?.segments[0];
61
66
  const last = itin?.segments[itin.segments.length - 1];
62
- return (_jsxs("section", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [_jsxs("header", { className: "mb-4 flex items-baseline justify-between gap-2", children: [_jsxs("h3", { className: "flex items-center gap-2 font-medium text-sm", children: [_jsx(Sparkles, { className: "h-4 w-4 text-muted-foreground" }), legLabel, " extras"] }), first && last && (_jsxs("span", { className: "text-muted-foreground text-xs", children: [first.departure.iataCode, " \u2192 ", last.arrival.iataCode] }))] }), _jsx("div", { className: "flex flex-col gap-4", children: passengers.map((pax) => (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("span", { className: "font-medium text-sm", children: pax.label }), _jsx("ul", { className: "flex flex-col gap-1.5", children: catalog.extras.map((opt) => {
67
+ return (_jsxs("section", { className: "rounded-xl border bg-card p-5 shadow-sm", children: [_jsxs("header", { className: "mb-4 flex items-baseline justify-between gap-2", children: [_jsxs("h3", { className: "flex items-center gap-2 font-medium text-sm", children: [_jsx(Sparkles, { className: "h-4 w-4 text-muted-foreground" }), formatMessage(messages.flightServicesStep.extras, { leg: legLabel })] }), first && last && (_jsxs("span", { className: "text-muted-foreground text-xs", children: [first.departure.iataCode, " \u2192 ", last.arrival.iataCode] }))] }), _jsx("div", { className: "flex flex-col gap-4", children: passengers.map((pax) => (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("span", { className: "font-medium text-sm", children: pax.label }), _jsx("ul", { className: "flex flex-col gap-1.5", children: catalog.extras.map((opt) => {
63
68
  const pick = value.find((v) => v.passengerId === pax.passengerId &&
64
69
  v.sliceIndex === sliceIndex &&
65
70
  v.optionId === opt.id);
@@ -71,32 +76,40 @@ function ExtraRow({ option, quantity, onChange, }) {
71
76
  return (_jsxs("li", { className: "flex items-center justify-between gap-3 rounded-md border bg-card px-3 py-2", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Package, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }), _jsx("span", { className: "truncate text-sm", children: option.label }), _jsx("span", { className: "font-mono text-[11px] text-muted-foreground", children: formatMoney(option.price.amount, option.price.currency) })] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx(Button, { type: "button", variant: "outline", size: "icon", className: "h-7 w-7", onClick: () => onChange(Math.max(0, quantity - 1)), disabled: quantity === 0, children: _jsx(Minus, { className: "h-3 w-3" }) }), _jsx("span", { className: "min-w-6 text-center font-medium text-sm tabular-nums", children: quantity }), _jsx(Button, { type: "button", variant: "outline", size: "icon", className: "h-7 w-7", onClick: () => onChange(Math.min(9, quantity + 1)), children: _jsx(Plus, { className: "h-3 w-3" }) })] })] }));
72
77
  }
73
78
  // ── Helpers ──────────────────────────────────────────────────────────────────
74
- function buildPassengerRows(passengers, counts) {
79
+ function buildPassengerRows(passengers, counts, messages) {
75
80
  if (passengers.length > 0) {
76
81
  return passengers.map((p) => ({
77
82
  passengerId: p.passengerId,
78
- label: nameOrFallback(p),
83
+ label: nameOrFallback(p, messages),
79
84
  }));
80
85
  }
81
86
  const out = [];
82
87
  for (let i = 1; i <= counts.adults; i++) {
83
- out.push({ passengerId: `pax_adult_${i}`, label: `Adult ${i}` });
88
+ out.push({
89
+ passengerId: `pax_adult_${i}`,
90
+ label: `${messages.common.passengerTypeLabels.adult} ${i}`,
91
+ });
84
92
  }
85
93
  for (let i = 1; i <= (counts.children ?? 0); i++) {
86
- out.push({ passengerId: `pax_child_${i}`, label: `Child ${i}` });
94
+ out.push({
95
+ passengerId: `pax_child_${i}`,
96
+ label: `${messages.common.passengerTypeLabels.child} ${i}`,
97
+ });
87
98
  }
88
99
  for (let i = 1; i <= (counts.infants ?? 0); i++) {
89
- out.push({ passengerId: `pax_infant_${i}`, label: `Infant ${i}` });
100
+ out.push({
101
+ passengerId: `pax_infant_${i}`,
102
+ label: `${messages.common.passengerTypeLabels.infant} ${i}`,
103
+ });
90
104
  }
91
105
  return out;
92
106
  }
93
- function nameOrFallback(p) {
107
+ function nameOrFallback(p, messages) {
94
108
  const full = `${p.firstName} ${p.lastName}`.trim();
95
109
  if (full)
96
110
  return full;
97
111
  const idx = p.passengerId.match(/_(\d+)$/)?.[1] ?? "1";
98
- const cap = p.type[0]?.toUpperCase() + p.type.slice(1);
99
- return `${cap} ${idx}`;
112
+ return `${messages.common.passengerTypeLabels[p.type]} ${idx}`;
100
113
  }
101
114
  function formatMoney(amount, currency) {
102
115
  const n = Number(amount);
@@ -1 +1 @@
1
- {"version":3,"file":"pax-cabin-popover.d.ts","sourceRoot":"","sources":["../../src/components/pax-cabin-popover.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAA;AAYnF,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,eAAe,CAAA;IAC3B,KAAK,EAAE,UAAU,CAAA;IACjB,QAAQ,EAAE,CAAC,IAAI,EAAE;QAAE,UAAU,EAAE,eAAe,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,CAAA;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AASD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,oBAAoB,2CAuE/F"}
1
+ {"version":3,"file":"pax-cabin-popover.d.ts","sourceRoot":"","sources":["../../src/components/pax-cabin-popover.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAA;AAcnF,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,eAAe,CAAA;IAC3B,KAAK,EAAE,UAAU,CAAA;IACjB,QAAQ,EAAE,CAAC,IAAI,EAAE;QAAE,UAAU,EAAE,eAAe,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,CAAA;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,oBAAoB,2CA6E/F"}
@@ -1,15 +1,11 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { formatMessage } from "@voyantjs/i18n";
3
4
  import { Button } from "@voyantjs/ui/components/button";
4
5
  import { Popover, PopoverContent, PopoverTrigger } from "@voyantjs/ui/components/popover";
5
6
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@voyantjs/ui/components/select";
6
7
  import { Minus, Plus, Users } from "lucide-react";
7
- const CABIN_LABEL = {
8
- economy: "Economy",
9
- premium_economy: "Premium economy",
10
- business: "Business",
11
- first: "First",
12
- };
8
+ import { useFlightsUiMessagesOrDefault } from "../i18n/index.js";
13
9
  /**
14
10
  * Compact pax + cabin selector — single trigger button summarizing
15
11
  * "2 adults · Economy" that opens a popover with steppers for each pax
@@ -17,8 +13,9 @@ const CABIN_LABEL = {
17
13
  * pattern; keeps the search form on one row.
18
14
  */
19
15
  export function PaxCabinPopover({ passengers, cabin, onChange, className }) {
16
+ const messages = useFlightsUiMessagesOrDefault();
20
17
  const total = passengers.adults + (passengers.children ?? 0) + (passengers.infants ?? 0);
21
- const summary = `${total} ${total === 1 ? "passenger" : "passengers"} · ${CABIN_LABEL[cabin]}`;
18
+ const summary = `${total} ${total === 1 ? messages.common.passengerSingular : messages.common.passengerPlural} · ${messages.common.cabinLabels[cabin]}`;
22
19
  const setCount = (key, value) => {
23
20
  onChange({
24
21
  passengers: {
@@ -28,11 +25,11 @@ export function PaxCabinPopover({ passengers, cabin, onChange, className }) {
28
25
  cabin,
29
26
  });
30
27
  };
31
- return (_jsxs(Popover, { children: [_jsxs(PopoverTrigger, { render: _jsx(Button, { type: "button", variant: "outline", size: "lg", className: className }), children: [_jsx(Users, { className: "h-4 w-4 text-muted-foreground" }), _jsx("span", { className: "text-sm", children: summary })] }), _jsx(PopoverContent, { align: "end", children: _jsxs("div", { className: "flex flex-col gap-3", children: [_jsx(PaxStepper, { label: "Adults", sublabel: "12+", value: passengers.adults, min: 1, onChange: (v) => setCount("adults", v) }), _jsx(PaxStepper, { label: "Children", sublabel: "2-11", value: passengers.children ?? 0, min: 0, onChange: (v) => setCount("children", v) }), _jsx(PaxStepper, { label: "Infants", sublabel: "under 2", value: passengers.infants ?? 0, min: 0, onChange: (v) => setCount("infants", v) }), _jsxs("div", { className: "mt-1 flex flex-col gap-1.5 border-t pt-3", children: [_jsx("span", { className: "text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: "Cabin" }), _jsxs(Select, { value: cabin, onValueChange: (v) => {
28
+ return (_jsxs(Popover, { children: [_jsxs(PopoverTrigger, { render: _jsx(Button, { type: "button", variant: "outline", size: "lg", className: className }), children: [_jsx(Users, { className: "h-4 w-4 text-muted-foreground" }), _jsx("span", { className: "text-sm", children: summary })] }), _jsx(PopoverContent, { align: "end", children: _jsxs("div", { className: "flex flex-col gap-3", children: [_jsx(PaxStepper, { label: messages.paxCabinPopover.adults, sublabel: messages.paxCabinPopover.adultsSublabel, value: passengers.adults, min: 1, onChange: (v) => setCount("adults", v), messages: messages }), _jsx(PaxStepper, { label: messages.paxCabinPopover.children, sublabel: messages.paxCabinPopover.childrenSublabel, value: passengers.children ?? 0, min: 0, onChange: (v) => setCount("children", v), messages: messages }), _jsx(PaxStepper, { label: messages.paxCabinPopover.infants, sublabel: messages.paxCabinPopover.infantsSublabel, value: passengers.infants ?? 0, min: 0, onChange: (v) => setCount("infants", v), messages: messages }), _jsxs("div", { className: "mt-1 flex flex-col gap-1.5 border-t pt-3", children: [_jsx("span", { className: "text-[11px] font-medium uppercase tracking-wider text-muted-foreground", children: messages.paxCabinPopover.cabin }), _jsxs(Select, { value: cabin, onValueChange: (v) => {
32
29
  if (v)
33
30
  onChange({ passengers, cabin: v });
34
- }, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: Object.keys(CABIN_LABEL).map((c) => (_jsx(SelectItem, { value: c, children: CABIN_LABEL[c] }, c))) })] })] })] }) })] }));
31
+ }, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: Object.keys(messages.common.cabinLabels).map((c) => (_jsx(SelectItem, { value: c, children: messages.common.cabinLabels[c] }, c))) })] })] })] }) })] }));
35
32
  }
36
- function PaxStepper({ label, sublabel, value, min, onChange, }) {
37
- return (_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex flex-col leading-tight", children: [_jsx("span", { className: "text-sm font-medium", children: label }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: sublabel })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { type: "button", variant: "outline", size: "icon", className: "h-7 w-7", onClick: () => onChange(value - 1), disabled: value <= min, "aria-label": `Decrease ${label}`, children: _jsx(Minus, { className: "h-3.5 w-3.5" }) }), _jsx("span", { className: "w-6 text-center text-sm font-medium tabular-nums", children: value }), _jsx(Button, { type: "button", variant: "outline", size: "icon", className: "h-7 w-7", onClick: () => onChange(value + 1), "aria-label": `Increase ${label}`, children: _jsx(Plus, { className: "h-3.5 w-3.5" }) })] })] }));
33
+ function PaxStepper({ label, sublabel, value, min, onChange, messages, }) {
34
+ return (_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex flex-col leading-tight", children: [_jsx("span", { className: "text-sm font-medium", children: label }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: sublabel })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { type: "button", variant: "outline", size: "icon", className: "h-7 w-7", onClick: () => onChange(value - 1), disabled: value <= min, "aria-label": formatMessage(messages.paxCabinPopover.decrease, { label }), children: _jsx(Minus, { className: "h-3.5 w-3.5" }) }), _jsx("span", { className: "w-6 text-center text-sm font-medium tabular-nums", children: value }), _jsx(Button, { type: "button", variant: "outline", size: "icon", className: "h-7 w-7", onClick: () => onChange(value + 1), "aria-label": formatMessage(messages.paxCabinPopover.increase, { label }), children: _jsx(Plus, { className: "h-3.5 w-3.5" }) })] })] }));
38
35
  }
@@ -30,11 +30,6 @@ export interface PopularRoutesProps {
30
30
  /** Section title; pass `null` to hide. */
31
31
  title?: string | null;
32
32
  }
33
- /**
34
- * Default route set — recognizable city pairs across regions so a fresh
35
- * /flights page has something to click without having to type airports.
36
- * Pages can pass their own `routes` to override.
37
- */
38
33
  export declare const DEFAULT_POPULAR_ROUTES: PopularRoute[];
39
34
  /**
40
35
  * A grid of clickable popular-route cards. Each card synthesizes a
@@ -1 +1 @@
1
- {"version":3,"file":"popular-routes.d.ts","sourceRoot":"","sources":["../../src/components/popular-routes.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAA;AAKvF,MAAM,WAAW,YAAY;IAC3B,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAA;IACd,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAA;IACnB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,gBAAgB,EAAE,MAAM,CAAA;IACxB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yCAAyC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,YAAY,EAAE,CAAA;IACtB,8EAA8E;IAC9E,QAAQ,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAA;IAChD,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,SAAS,GAAG,YAAY,CAAA;IACnC,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,oEAAoE;IACpE,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,YAAY,EAiFhD,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,QAAQ,EACR,QAAuB,EACvB,OAAY,EACZ,UAAc,EACd,KAAiB,EACjB,MAAU,EACV,SAAS,EACT,KAAwB,GACzB,EAAE,kBAAkB,2CA2DpB"}
1
+ {"version":3,"file":"popular-routes.d.ts","sourceRoot":"","sources":["../../src/components/popular-routes.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAA;AAOvF,MAAM,WAAW,YAAY;IAC3B,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAA;IACd,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAA;IACnB,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,gBAAgB,EAAE,MAAM,CAAA;IACxB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yCAAyC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,YAAY,EAAE,CAAA;IACtB,8EAA8E;IAC9E,QAAQ,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAA;IAChD,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,SAAS,GAAG,YAAY,CAAA;IACnC,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,oEAAoE;IACpE,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB;AAkDD,eAAO,MAAM,sBAAsB,EAAE,YAAY,EAKhD,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,QAAQ,EACR,QAAuB,EACvB,OAAY,EACZ,UAAc,EACd,KAAiB,EACjB,MAAU,EACV,SAAS,EACT,KAAK,GACN,EAAE,kBAAkB,2CAqEpB"}