@voyant-travel/bookings-react 0.119.3
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.
- package/LICENSE +201 -0
- package/README.md +87 -0
- package/dist/admin/booking-contract-dialog.d.ts +22 -0
- package/dist/admin/booking-contract-dialog.d.ts.map +1 -0
- package/dist/admin/booking-contract-dialog.js +161 -0
- package/dist/admin/booking-detail-host.d.ts +103 -0
- package/dist/admin/booking-detail-host.d.ts.map +1 -0
- package/dist/admin/booking-detail-host.js +127 -0
- package/dist/admin/booking-detail-skeleton.d.ts +7 -0
- package/dist/admin/booking-detail-skeleton.d.ts.map +1 -0
- package/dist/admin/booking-detail-skeleton.js +24 -0
- package/dist/admin/booking-documents-table.d.ts +13 -0
- package/dist/admin/booking-documents-table.d.ts.map +1 -0
- package/dist/admin/booking-documents-table.js +259 -0
- package/dist/admin/booking-invoice-sheet.d.ts +18 -0
- package/dist/admin/booking-invoice-sheet.d.ts.map +1 -0
- package/dist/admin/booking-invoice-sheet.js +101 -0
- package/dist/admin/booking-journey-host.d.ts +24 -0
- package/dist/admin/booking-journey-host.d.ts.map +1 -0
- package/dist/admin/booking-journey-host.js +278 -0
- package/dist/admin/bookings-host.d.ts +26 -0
- package/dist/admin/bookings-host.d.ts.map +1 -0
- package/dist/admin/bookings-host.js +18 -0
- package/dist/admin/bookings-list-skeleton.d.ts +10 -0
- package/dist/admin/bookings-list-skeleton.d.ts.map +1 -0
- package/dist/admin/bookings-list-skeleton.js +25 -0
- package/dist/admin/index.d.ts +273 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +331 -0
- package/dist/admin/journey-billing-duplicate-warning.d.ts +3 -0
- package/dist/admin/journey-billing-duplicate-warning.d.ts.map +1 -0
- package/dist/admin/journey-billing-duplicate-warning.js +26 -0
- package/dist/admin/journey-departure-picker.d.ts +7 -0
- package/dist/admin/journey-departure-picker.d.ts.map +1 -0
- package/dist/admin/journey-departure-picker.js +100 -0
- package/dist/admin/journey-units-picker.d.ts +11 -0
- package/dist/admin/journey-units-picker.d.ts.map +1 -0
- package/dist/admin/journey-units-picker.js +60 -0
- package/dist/admin/journey-voucher-picker.d.ts +3 -0
- package/dist/admin/journey-voucher-picker.d.ts.map +1 -0
- package/dist/admin/journey-voucher-picker.js +71 -0
- package/dist/admin/pages/booking-compose-page.d.ts +9 -0
- package/dist/admin/pages/booking-compose-page.d.ts.map +1 -0
- package/dist/admin/pages/booking-compose-page.js +17 -0
- package/dist/admin/pages/booking-detail-page.d.ts +11 -0
- package/dist/admin/pages/booking-detail-page.d.ts.map +1 -0
- package/dist/admin/pages/booking-detail-page.js +14 -0
- package/dist/admin/pages/booking-journey-page.d.ts +12 -0
- package/dist/admin/pages/booking-journey-page.d.ts.map +1 -0
- package/dist/admin/pages/booking-journey-page.js +26 -0
- package/dist/admin/pages/booking-new-page.d.ts +15 -0
- package/dist/admin/pages/booking-new-page.d.ts.map +1 -0
- package/dist/admin/pages/booking-new-page.js +50 -0
- package/dist/admin/pages/bookings-index-page.d.ts +20 -0
- package/dist/admin/pages/bookings-index-page.d.ts.map +1 -0
- package/dist/admin/pages/bookings-index-page.js +18 -0
- package/dist/admin/person-bookings-widget.d.ts +13 -0
- package/dist/admin/person-bookings-widget.d.ts.map +1 -0
- package/dist/admin/person-bookings-widget.js +48 -0
- package/dist/admin/slots.d.ts +31 -0
- package/dist/admin/slots.d.ts.map +1 -0
- package/dist/admin/slots.js +30 -0
- package/dist/admin/use-booking-action-ledger-events.d.ts +15 -0
- package/dist/admin/use-booking-action-ledger-events.d.ts.map +1 -0
- package/dist/admin/use-booking-action-ledger-events.js +66 -0
- package/dist/client.d.ts +14 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +59 -0
- package/dist/components/booking-activity-timeline.d.ts +32 -0
- package/dist/components/booking-activity-timeline.d.ts.map +1 -0
- package/dist/components/booking-activity-timeline.js +147 -0
- package/dist/components/booking-billing-dialog.d.ts +16 -0
- package/dist/components/booking-billing-dialog.d.ts.map +1 -0
- package/dist/components/booking-billing-dialog.js +315 -0
- package/dist/components/booking-cancellation-dialog.d.ts +18 -0
- package/dist/components/booking-cancellation-dialog.d.ts.map +1 -0
- package/dist/components/booking-cancellation-dialog.js +79 -0
- package/dist/components/booking-combobox.d.ts +13 -0
- package/dist/components/booking-combobox.d.ts.map +1 -0
- package/dist/components/booking-combobox.js +44 -0
- package/dist/components/booking-create-form-utils.d.ts +56 -0
- package/dist/components/booking-create-form-utils.d.ts.map +1 -0
- package/dist/components/booking-create-form-utils.js +216 -0
- package/dist/components/booking-create-page.d.ts +14 -0
- package/dist/components/booking-create-page.d.ts.map +1 -0
- package/dist/components/booking-create-page.js +11 -0
- package/dist/components/booking-create-preview-card.d.ts +26 -0
- package/dist/components/booking-create-preview-card.d.ts.map +1 -0
- package/dist/components/booking-create-preview-card.js +107 -0
- package/dist/components/booking-create-product-extras-picker.d.ts +18 -0
- package/dist/components/booking-create-product-extras-picker.d.ts.map +1 -0
- package/dist/components/booking-create-product-extras-picker.js +82 -0
- package/dist/components/booking-create-sheet.d.ts +34 -0
- package/dist/components/booking-create-sheet.d.ts.map +1 -0
- package/dist/components/booking-create-sheet.js +811 -0
- package/dist/components/booking-create-utils.d.ts +66 -0
- package/dist/components/booking-create-utils.d.ts.map +1 -0
- package/dist/components/booking-create-utils.js +185 -0
- package/dist/components/booking-detail-page.d.ts +126 -0
- package/dist/components/booking-detail-page.d.ts.map +1 -0
- package/dist/components/booking-detail-page.js +264 -0
- package/dist/components/booking-dialog.d.ts +28 -0
- package/dist/components/booking-dialog.d.ts.map +1 -0
- package/dist/components/booking-dialog.js +130 -0
- package/dist/components/booking-document-dialog.d.ts +8 -0
- package/dist/components/booking-document-dialog.d.ts.map +1 -0
- package/dist/components/booking-document-dialog.js +83 -0
- package/dist/components/booking-document-list.d.ts +5 -0
- package/dist/components/booking-document-list.d.ts.map +1 -0
- package/dist/components/booking-document-list.js +43 -0
- package/dist/components/booking-group-link-dialog.d.ts +10 -0
- package/dist/components/booking-group-link-dialog.d.ts.map +1 -0
- package/dist/components/booking-group-link-dialog.js +79 -0
- package/dist/components/booking-group-section.d.ts +27 -0
- package/dist/components/booking-group-section.d.ts.map +1 -0
- package/dist/components/booking-group-section.js +51 -0
- package/dist/components/booking-guarantee-dialog.d.ts +10 -0
- package/dist/components/booking-guarantee-dialog.d.ts.map +1 -0
- package/dist/components/booking-guarantee-dialog.js +123 -0
- package/dist/components/booking-guarantee-list.d.ts +5 -0
- package/dist/components/booking-guarantee-list.d.ts.map +1 -0
- package/dist/components/booking-guarantee-list.js +86 -0
- package/dist/components/booking-item-dialog.d.ts +10 -0
- package/dist/components/booking-item-dialog.d.ts.map +1 -0
- package/dist/components/booking-item-dialog.js +155 -0
- package/dist/components/booking-item-list.d.ts +12 -0
- package/dist/components/booking-item-list.d.ts.map +1 -0
- package/dist/components/booking-item-list.js +191 -0
- package/dist/components/booking-item-travelers.d.ts +6 -0
- package/dist/components/booking-item-travelers.d.ts.map +1 -0
- package/dist/components/booking-item-travelers.js +57 -0
- package/dist/components/booking-list-filters.d.ts +43 -0
- package/dist/components/booking-list-filters.d.ts.map +1 -0
- package/dist/components/booking-list-filters.js +192 -0
- package/dist/components/booking-list.d.ts +50 -0
- package/dist/components/booking-list.d.ts.map +1 -0
- package/dist/components/booking-list.js +352 -0
- package/dist/components/booking-note-dialog.d.ts +16 -0
- package/dist/components/booking-note-dialog.d.ts.map +1 -0
- package/dist/components/booking-note-dialog.js +41 -0
- package/dist/components/booking-notes.d.ts +5 -0
- package/dist/components/booking-notes.d.ts.map +1 -0
- package/dist/components/booking-notes.js +45 -0
- package/dist/components/booking-payment-reconciliation-banner.d.ts +5 -0
- package/dist/components/booking-payment-reconciliation-banner.d.ts.map +1 -0
- package/dist/components/booking-payment-reconciliation-banner.js +91 -0
- package/dist/components/booking-payment-schedule-dialog.d.ts +10 -0
- package/dist/components/booking-payment-schedule-dialog.d.ts.map +1 -0
- package/dist/components/booking-payment-schedule-dialog.js +117 -0
- package/dist/components/booking-payment-schedule-list.d.ts +10 -0
- package/dist/components/booking-payment-schedule-list.d.ts.map +1 -0
- package/dist/components/booking-payment-schedule-list.js +217 -0
- package/dist/components/booking-payments-summary.d.ts +83 -0
- package/dist/components/booking-payments-summary.d.ts.map +1 -0
- package/dist/components/booking-payments-summary.js +176 -0
- package/dist/components/booking-quick-view-sheet.d.ts +14 -0
- package/dist/components/booking-quick-view-sheet.d.ts.map +1 -0
- package/dist/components/booking-quick-view-sheet.js +283 -0
- package/dist/components/bookings-page.d.ts +19 -0
- package/dist/components/bookings-page.d.ts.map +1 -0
- package/dist/components/bookings-page.js +9 -0
- package/dist/components/file-dropzone.d.ts +25 -0
- package/dist/components/file-dropzone.d.ts.map +1 -0
- package/dist/components/file-dropzone.js +102 -0
- package/dist/components/icon-action-button.d.ts +18 -0
- package/dist/components/icon-action-button.d.ts.map +1 -0
- package/dist/components/icon-action-button.js +13 -0
- package/dist/components/option-units-stepper-section.d.ts +111 -0
- package/dist/components/option-units-stepper-section.d.ts.map +1 -0
- package/dist/components/option-units-stepper-section.js +276 -0
- package/dist/components/payment-schedule-section.d.ts +91 -0
- package/dist/components/payment-schedule-section.d.ts.map +1 -0
- package/dist/components/payment-schedule-section.js +206 -0
- package/dist/components/person-picker-section.d.ts +71 -0
- package/dist/components/person-picker-section.d.ts.map +1 -0
- package/dist/components/person-picker-section.js +160 -0
- package/dist/components/price-breakdown-section.d.ts +83 -0
- package/dist/components/price-breakdown-section.d.ts.map +1 -0
- package/dist/components/price-breakdown-section.js +278 -0
- package/dist/components/product-picker-section.d.ts +29 -0
- package/dist/components/product-picker-section.d.ts.map +1 -0
- package/dist/components/product-picker-section.js +74 -0
- package/dist/components/shared-room-section.d.ts +40 -0
- package/dist/components/shared-room-section.d.ts.map +1 -0
- package/dist/components/shared-room-section.js +99 -0
- package/dist/components/status-badge.d.ts +24 -0
- package/dist/components/status-badge.d.ts.map +1 -0
- package/dist/components/status-badge.js +65 -0
- package/dist/components/status-change-dialog.d.ts +10 -0
- package/dist/components/status-change-dialog.d.ts.map +1 -0
- package/dist/components/status-change-dialog.js +57 -0
- package/dist/components/supplier-status-dialog.d.ts +10 -0
- package/dist/components/supplier-status-dialog.d.ts.map +1 -0
- package/dist/components/supplier-status-dialog.js +98 -0
- package/dist/components/supplier-status-list.d.ts +5 -0
- package/dist/components/supplier-status-list.d.ts.map +1 -0
- package/dist/components/supplier-status-list.js +115 -0
- package/dist/components/traveler-category-buttons.d.ts +26 -0
- package/dist/components/traveler-category-buttons.d.ts.map +1 -0
- package/dist/components/traveler-category-buttons.js +35 -0
- package/dist/components/traveler-dialog.d.ts +10 -0
- package/dist/components/traveler-dialog.d.ts.map +1 -0
- package/dist/components/traveler-dialog.js +256 -0
- package/dist/components/traveler-list.d.ts +6 -0
- package/dist/components/traveler-list.d.ts.map +1 -0
- package/dist/components/traveler-list.js +295 -0
- package/dist/components/travelers-section-controls.d.ts +52 -0
- package/dist/components/travelers-section-controls.d.ts.map +1 -0
- package/dist/components/travelers-section-controls.js +206 -0
- package/dist/components/travelers-section.d.ts +159 -0
- package/dist/components/travelers-section.d.ts.map +1 -0
- package/dist/components/travelers-section.js +355 -0
- package/dist/components/voucher-picker-section.d.ts +50 -0
- package/dist/components/voucher-picker-section.d.ts.map +1 -0
- package/dist/components/voucher-picker-section.js +79 -0
- package/dist/extras/client.d.ts +14 -0
- package/dist/extras/client.d.ts.map +1 -0
- package/dist/extras/client.js +58 -0
- package/dist/extras/components/extra-catalog-card.d.ts +13 -0
- package/dist/extras/components/extra-catalog-card.d.ts.map +1 -0
- package/dist/extras/components/extra-catalog-card.js +52 -0
- package/dist/extras/components/product-combobox.d.ts +9 -0
- package/dist/extras/components/product-combobox.d.ts.map +1 -0
- package/dist/extras/components/product-combobox.js +46 -0
- package/dist/extras/components/slot-extras-manifest-panel.d.ts +6 -0
- package/dist/extras/components/slot-extras-manifest-panel.d.ts.map +1 -0
- package/dist/extras/components/slot-extras-manifest-panel.js +108 -0
- package/dist/extras/hooks/index.d.ts +5 -0
- package/dist/extras/hooks/index.d.ts.map +1 -0
- package/dist/extras/hooks/index.js +4 -0
- package/dist/extras/hooks/use-product-extra.d.ts +24 -0
- package/dist/extras/hooks/use-product-extra.d.ts.map +1 -0
- package/dist/extras/hooks/use-product-extra.js +12 -0
- package/dist/extras/hooks/use-product-extras.d.ts +30 -0
- package/dist/extras/hooks/use-product-extras.d.ts.map +1 -0
- package/dist/extras/hooks/use-product-extras.js +12 -0
- package/dist/extras/hooks/use-slot-extra-manifest-mutation.d.ts +48 -0
- package/dist/extras/hooks/use-slot-extra-manifest-mutation.d.ts.map +1 -0
- package/dist/extras/hooks/use-slot-extra-manifest-mutation.js +26 -0
- package/dist/extras/hooks/use-slot-extra-manifest.d.ts +68 -0
- package/dist/extras/hooks/use-slot-extra-manifest.d.ts.map +1 -0
- package/dist/extras/hooks/use-slot-extra-manifest.js +11 -0
- package/dist/extras/i18n/en.d.ts +52 -0
- package/dist/extras/i18n/en.d.ts.map +1 -0
- package/dist/extras/i18n/en.js +51 -0
- package/dist/extras/i18n/index.d.ts +5 -0
- package/dist/extras/i18n/index.d.ts.map +1 -0
- package/dist/extras/i18n/index.js +3 -0
- package/dist/extras/i18n/messages.d.ts +37 -0
- package/dist/extras/i18n/messages.d.ts.map +1 -0
- package/dist/extras/i18n/messages.js +1 -0
- package/dist/extras/i18n/provider.d.ts +126 -0
- package/dist/extras/i18n/provider.d.ts.map +1 -0
- package/dist/extras/i18n/provider.js +44 -0
- package/dist/extras/i18n/ro.d.ts +52 -0
- package/dist/extras/i18n/ro.d.ts.map +1 -0
- package/dist/extras/i18n/ro.js +51 -0
- package/dist/extras/index.d.ts +7 -0
- package/dist/extras/index.d.ts.map +1 -0
- package/dist/extras/index.js +6 -0
- package/dist/extras/provider.d.ts +2 -0
- package/dist/extras/provider.d.ts.map +1 -0
- package/dist/extras/provider.js +1 -0
- package/dist/extras/query-keys.d.ts +16 -0
- package/dist/extras/query-keys.d.ts.map +1 -0
- package/dist/extras/query-keys.js +8 -0
- package/dist/extras/query-options.d.ts +455 -0
- package/dist/extras/query-options.d.ts.map +1 -0
- package/dist/extras/query-options.js +44 -0
- package/dist/extras/schemas.d.ts +416 -0
- package/dist/extras/schemas.d.ts.map +1 -0
- package/dist/extras/schemas.js +89 -0
- package/dist/extras/ui.d.ts +4 -0
- package/dist/extras/ui.d.ts.map +1 -0
- package/dist/extras/ui.js +3 -0
- package/dist/extras.d.ts +10 -0
- package/dist/extras.d.ts.map +1 -0
- package/dist/extras.js +9 -0
- package/dist/hooks/index.d.ts +36 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +35 -0
- package/dist/hooks/use-booking-action-ledger.d.ts +63 -0
- package/dist/hooks/use-booking-action-ledger.d.ts.map +1 -0
- package/dist/hooks/use-booking-action-ledger.js +34 -0
- package/dist/hooks/use-booking-activity.d.ts +17 -0
- package/dist/hooks/use-booking-activity.d.ts.map +1 -0
- package/dist/hooks/use-booking-activity.js +12 -0
- package/dist/hooks/use-booking-cancel-mutation.d.ts +69 -0
- package/dist/hooks/use-booking-cancel-mutation.d.ts.map +1 -0
- package/dist/hooks/use-booking-cancel-mutation.js +24 -0
- package/dist/hooks/use-booking-contract-generation.d.ts +31 -0
- package/dist/hooks/use-booking-contract-generation.d.ts.map +1 -0
- package/dist/hooks/use-booking-contract-generation.js +36 -0
- package/dist/hooks/use-booking-convert-mutation.d.ts +81 -0
- package/dist/hooks/use-booking-convert-mutation.d.ts.map +1 -0
- package/dist/hooks/use-booking-convert-mutation.js +24 -0
- package/dist/hooks/use-booking-create-mutation.d.ts +337 -0
- package/dist/hooks/use-booking-create-mutation.d.ts.map +1 -0
- package/dist/hooks/use-booking-create-mutation.js +43 -0
- package/dist/hooks/use-booking-documents.d.ts +41 -0
- package/dist/hooks/use-booking-documents.d.ts.map +1 -0
- package/dist/hooks/use-booking-documents.js +46 -0
- package/dist/hooks/use-booking-dual-create-mutation.d.ts +338 -0
- package/dist/hooks/use-booking-dual-create-mutation.d.ts.map +1 -0
- package/dist/hooks/use-booking-dual-create-mutation.js +45 -0
- package/dist/hooks/use-booking-group-for-booking.d.ts +24 -0
- package/dist/hooks/use-booking-group-for-booking.d.ts.map +1 -0
- package/dist/hooks/use-booking-group-for-booking.js +12 -0
- package/dist/hooks/use-booking-group-member-mutation.d.ts +27 -0
- package/dist/hooks/use-booking-group-member-mutation.d.ts.map +1 -0
- package/dist/hooks/use-booking-group-member-mutation.js +38 -0
- package/dist/hooks/use-booking-group-mutation.d.ts +40 -0
- package/dist/hooks/use-booking-group-mutation.d.ts.map +1 -0
- package/dist/hooks/use-booking-group-mutation.js +32 -0
- package/dist/hooks/use-booking-group.d.ts +85 -0
- package/dist/hooks/use-booking-group.d.ts.map +1 -0
- package/dist/hooks/use-booking-group.js +12 -0
- package/dist/hooks/use-booking-groups.d.ts +21 -0
- package/dist/hooks/use-booking-groups.d.ts.map +1 -0
- package/dist/hooks/use-booking-groups.js +12 -0
- package/dist/hooks/use-booking-item-mutation.d.ts +101 -0
- package/dist/hooks/use-booking-item-mutation.d.ts.map +1 -0
- package/dist/hooks/use-booking-item-mutation.js +42 -0
- package/dist/hooks/use-booking-item-travelers.d.ts +32 -0
- package/dist/hooks/use-booking-item-travelers.d.ts.map +1 -0
- package/dist/hooks/use-booking-item-travelers.js +48 -0
- package/dist/hooks/use-booking-items.d.ts +36 -0
- package/dist/hooks/use-booking-items.d.ts.map +1 -0
- package/dist/hooks/use-booking-items.js +12 -0
- package/dist/hooks/use-booking-mutation.d.ts +158 -0
- package/dist/hooks/use-booking-mutation.d.ts.map +1 -0
- package/dist/hooks/use-booking-mutation.js +39 -0
- package/dist/hooks/use-booking-note-mutation.d.ts +39 -0
- package/dist/hooks/use-booking-note-mutation.d.ts.map +1 -0
- package/dist/hooks/use-booking-note-mutation.js +44 -0
- package/dist/hooks/use-booking-notes.d.ts +15 -0
- package/dist/hooks/use-booking-notes.d.ts.map +1 -0
- package/dist/hooks/use-booking-notes.js +12 -0
- package/dist/hooks/use-booking-primary-product.d.ts +28 -0
- package/dist/hooks/use-booking-primary-product.d.ts.map +1 -0
- package/dist/hooks/use-booking-primary-product.js +20 -0
- package/dist/hooks/use-booking-status-mutation.d.ts +156 -0
- package/dist/hooks/use-booking-status-mutation.d.ts.map +1 -0
- package/dist/hooks/use-booking-status-mutation.js +54 -0
- package/dist/hooks/use-booking-tax-preview.d.ts +29 -0
- package/dist/hooks/use-booking-tax-preview.d.ts.map +1 -0
- package/dist/hooks/use-booking-tax-preview.js +21 -0
- package/dist/hooks/use-booking.d.ts +67 -0
- package/dist/hooks/use-booking.d.ts.map +1 -0
- package/dist/hooks/use-booking.js +12 -0
- package/dist/hooks/use-bookings.d.ts +71 -0
- package/dist/hooks/use-bookings.d.ts.map +1 -0
- package/dist/hooks/use-bookings.js +12 -0
- package/dist/hooks/use-pricing-preview.d.ts +61 -0
- package/dist/hooks/use-pricing-preview.d.ts.map +1 -0
- package/dist/hooks/use-pricing-preview.js +18 -0
- package/dist/hooks/use-public-booking-session-flow-mutation.d.ts +148 -0
- package/dist/hooks/use-public-booking-session-flow-mutation.d.ts.map +1 -0
- package/dist/hooks/use-public-booking-session-flow-mutation.js +35 -0
- package/dist/hooks/use-public-booking-session-state.d.ts +16 -0
- package/dist/hooks/use-public-booking-session-state.d.ts.map +1 -0
- package/dist/hooks/use-public-booking-session-state.js +12 -0
- package/dist/hooks/use-public-booking-session.d.ts +101 -0
- package/dist/hooks/use-public-booking-session.d.ts.map +1 -0
- package/dist/hooks/use-public-booking-session.js +12 -0
- package/dist/hooks/use-reveal-traveler.d.ts +54 -0
- package/dist/hooks/use-reveal-traveler.d.ts.map +1 -0
- package/dist/hooks/use-reveal-traveler.js +18 -0
- package/dist/hooks/use-sharing-groups.d.ts +41 -0
- package/dist/hooks/use-sharing-groups.d.ts.map +1 -0
- package/dist/hooks/use-sharing-groups.js +20 -0
- package/dist/hooks/use-supplier-status-mutation.d.ts +46 -0
- package/dist/hooks/use-supplier-status-mutation.d.ts.map +1 -0
- package/dist/hooks/use-supplier-status-mutation.js +39 -0
- package/dist/hooks/use-supplier-statuses.d.ts +20 -0
- package/dist/hooks/use-supplier-statuses.d.ts.map +1 -0
- package/dist/hooks/use-supplier-statuses.js +12 -0
- package/dist/hooks/use-traveler-mutation.d.ts +55 -0
- package/dist/hooks/use-traveler-mutation.d.ts.map +1 -0
- package/dist/hooks/use-traveler-mutation.js +42 -0
- package/dist/hooks/use-traveler-with-travel-details-mutation.d.ts +120 -0
- package/dist/hooks/use-traveler-with-travel-details-mutation.d.ts.map +1 -0
- package/dist/hooks/use-traveler-with-travel-details-mutation.js +43 -0
- package/dist/hooks/use-travelers.d.ts +23 -0
- package/dist/hooks/use-travelers.d.ts.map +1 -0
- package/dist/hooks/use-travelers.js +12 -0
- package/dist/i18n/en-base.d.ts +295 -0
- package/dist/i18n/en-base.d.ts.map +1 -0
- package/dist/i18n/en-base.js +294 -0
- package/dist/i18n/en-create-list.d.ts +327 -0
- package/dist/i18n/en-create-list.d.ts.map +1 -0
- package/dist/i18n/en-create-list.js +326 -0
- package/dist/i18n/en-journey.d.ts +229 -0
- package/dist/i18n/en-journey.d.ts.map +1 -0
- package/dist/i18n/en-journey.js +228 -0
- package/dist/i18n/en-operations.d.ts +382 -0
- package/dist/i18n/en-operations.d.ts.map +1 -0
- package/dist/i18n/en-operations.js +381 -0
- package/dist/i18n/en-sections.d.ts +360 -0
- package/dist/i18n/en-sections.d.ts.map +1 -0
- package/dist/i18n/en-sections.js +359 -0
- package/dist/i18n/en.d.ts +1581 -0
- package/dist/i18n/en.d.ts.map +1 -0
- package/dist/i18n/en.js +12 -0
- package/dist/i18n/index.d.ts +5 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +3 -0
- package/dist/i18n/messages-base.d.ts +251 -0
- package/dist/i18n/messages-base.d.ts.map +1 -0
- package/dist/i18n/messages-base.js +1 -0
- package/dist/i18n/messages-create-list.d.ts +310 -0
- package/dist/i18n/messages-create-list.d.ts.map +1 -0
- package/dist/i18n/messages-create-list.js +1 -0
- package/dist/i18n/messages-journey.d.ts +198 -0
- package/dist/i18n/messages-journey.d.ts.map +1 -0
- package/dist/i18n/messages-journey.js +1 -0
- package/dist/i18n/messages-operations.d.ts +362 -0
- package/dist/i18n/messages-operations.d.ts.map +1 -0
- package/dist/i18n/messages-operations.js +1 -0
- package/dist/i18n/messages-sections.d.ts +312 -0
- package/dist/i18n/messages-sections.d.ts.map +1 -0
- package/dist/i18n/messages-sections.js +1 -0
- package/dist/i18n/messages.d.ts +7 -0
- package/dist/i18n/messages.d.ts.map +1 -0
- package/dist/i18n/messages.js +1 -0
- package/dist/i18n/provider.d.ts +3185 -0
- package/dist/i18n/provider.d.ts.map +1 -0
- package/dist/i18n/provider.js +45 -0
- package/dist/i18n/ro-base.d.ts +295 -0
- package/dist/i18n/ro-base.d.ts.map +1 -0
- package/dist/i18n/ro-base.js +294 -0
- package/dist/i18n/ro-create-list.d.ts +327 -0
- package/dist/i18n/ro-create-list.d.ts.map +1 -0
- package/dist/i18n/ro-create-list.js +326 -0
- package/dist/i18n/ro-journey.d.ts +229 -0
- package/dist/i18n/ro-journey.d.ts.map +1 -0
- package/dist/i18n/ro-journey.js +228 -0
- package/dist/i18n/ro-operations.d.ts +382 -0
- package/dist/i18n/ro-operations.d.ts.map +1 -0
- package/dist/i18n/ro-operations.js +381 -0
- package/dist/i18n/ro-sections.d.ts +360 -0
- package/dist/i18n/ro-sections.d.ts.map +1 -0
- package/dist/i18n/ro-sections.js +359 -0
- package/dist/i18n/ro.d.ts +1581 -0
- package/dist/i18n/ro.d.ts.map +1 -0
- package/dist/i18n/ro.js +12 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/journey/components/booking-journey-rules.d.ts +48 -0
- package/dist/journey/components/booking-journey-rules.d.ts.map +1 -0
- package/dist/journey/components/booking-journey-rules.js +235 -0
- package/dist/journey/components/booking-journey.d.ts +3 -0
- package/dist/journey/components/booking-journey.d.ts.map +1 -0
- package/dist/journey/components/booking-journey.js +368 -0
- package/dist/journey/components/configure-step-skeleton.d.ts +8 -0
- package/dist/journey/components/configure-step-skeleton.d.ts.map +1 -0
- package/dist/journey/components/configure-step-skeleton.js +11 -0
- package/dist/journey/components/contract-preview-dialog.d.ts +47 -0
- package/dist/journey/components/contract-preview-dialog.d.ts.map +1 -0
- package/dist/journey/components/contract-preview-dialog.js +124 -0
- package/dist/journey/components/journey-steps/accommodation-step.d.ts +3 -0
- package/dist/journey/components/journey-steps/accommodation-step.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/accommodation-step.js +71 -0
- package/dist/journey/components/journey-steps/addons-step.d.ts +3 -0
- package/dist/journey/components/journey-steps/addons-step.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/addons-step.js +40 -0
- package/dist/journey/components/journey-steps/billing-step.d.ts +8 -0
- package/dist/journey/components/journey-steps/billing-step.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/billing-step.js +78 -0
- package/dist/journey/components/journey-steps/configure-steps.d.ts +28 -0
- package/dist/journey/components/journey-steps/configure-steps.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/configure-steps.js +232 -0
- package/dist/journey/components/journey-steps/documents-step.d.ts +11 -0
- package/dist/journey/components/journey-steps/documents-step.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/documents-step.js +36 -0
- package/dist/journey/components/journey-steps/payment-step.d.ts +29 -0
- package/dist/journey/components/journey-steps/payment-step.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/payment-step.js +225 -0
- package/dist/journey/components/journey-steps/review-step.d.ts +27 -0
- package/dist/journey/components/journey-steps/review-step.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/review-step.js +18 -0
- package/dist/journey/components/journey-steps/shared.d.ts +75 -0
- package/dist/journey/components/journey-steps/shared.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/shared.js +108 -0
- package/dist/journey/components/journey-steps/travelers-step.d.ts +7 -0
- package/dist/journey/components/journey-steps/travelers-step.d.ts.map +1 -0
- package/dist/journey/components/journey-steps/travelers-step.js +201 -0
- package/dist/journey/components/journey-steps.d.ts +21 -0
- package/dist/journey/components/journey-steps.d.ts.map +1 -0
- package/dist/journey/components/journey-steps.js +20 -0
- package/dist/journey/components/side-panel.d.ts +17 -0
- package/dist/journey/components/side-panel.d.ts.map +1 -0
- package/dist/journey/components/side-panel.js +245 -0
- package/dist/journey/components/stacked-journey.d.ts +30 -0
- package/dist/journey/components/stacked-journey.d.ts.map +1 -0
- package/dist/journey/components/stacked-journey.js +50 -0
- package/dist/journey/components/step-header.d.ts +7 -0
- package/dist/journey/components/step-header.d.ts.map +1 -0
- package/dist/journey/components/step-header.js +12 -0
- package/dist/journey/index.d.ts +18 -0
- package/dist/journey/index.d.ts.map +1 -0
- package/dist/journey/index.js +17 -0
- package/dist/journey/lib/draft-state.d.ts +35 -0
- package/dist/journey/lib/draft-state.d.ts.map +1 -0
- package/dist/journey/lib/draft-state.js +57 -0
- package/dist/journey/lib/pax-band-dependencies.d.ts +27 -0
- package/dist/journey/lib/pax-band-dependencies.d.ts.map +1 -0
- package/dist/journey/lib/pax-band-dependencies.js +50 -0
- package/dist/journey/lib/payment-schedule.d.ts +19 -0
- package/dist/journey/lib/payment-schedule.d.ts.map +1 -0
- package/dist/journey/lib/payment-schedule.js +90 -0
- package/dist/journey/types.d.ts +403 -0
- package/dist/journey/types.d.ts.map +1 -0
- package/dist/journey/types.js +19 -0
- package/dist/provider.d.ts +2 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +1 -0
- package/dist/query-keys.d.ts +74 -0
- package/dist/query-keys.d.ts.map +1 -0
- package/dist/query-keys.js +26 -0
- package/dist/query-options.d.ts +2534 -0
- package/dist/query-options.d.ts.map +1 -0
- package/dist/query-options.js +233 -0
- package/dist/requirements/client.d.ts +14 -0
- package/dist/requirements/client.d.ts.map +1 -0
- package/dist/requirements/client.js +59 -0
- package/dist/requirements/components/booking-requirements-contact-tab.d.ts +8 -0
- package/dist/requirements/components/booking-requirements-contact-tab.d.ts.map +1 -0
- package/dist/requirements/components/booking-requirements-contact-tab.js +8 -0
- package/dist/requirements/components/booking-requirements-questions-tab.d.ts +14 -0
- package/dist/requirements/components/booking-requirements-questions-tab.d.ts.map +1 -0
- package/dist/requirements/components/booking-requirements-questions-tab.js +17 -0
- package/dist/requirements/constants.d.ts +114 -0
- package/dist/requirements/constants.d.ts.map +1 -0
- package/dist/requirements/constants.js +45 -0
- package/dist/requirements/hooks/index.d.ts +6 -0
- package/dist/requirements/hooks/index.d.ts.map +1 -0
- package/dist/requirements/hooks/index.js +6 -0
- package/dist/requirements/hooks/use-booking-questions.d.ts +24 -0
- package/dist/requirements/hooks/use-booking-questions.d.ts.map +1 -0
- package/dist/requirements/hooks/use-booking-questions.js +9 -0
- package/dist/requirements/hooks/use-contact-requirements.d.ts +22 -0
- package/dist/requirements/hooks/use-contact-requirements.d.ts.map +1 -0
- package/dist/requirements/hooks/use-contact-requirements.js +9 -0
- package/dist/requirements/hooks/use-products.d.ts +16 -0
- package/dist/requirements/hooks/use-products.d.ts.map +1 -0
- package/dist/requirements/hooks/use-products.js +9 -0
- package/dist/requirements/hooks/use-question-options.d.ts +19 -0
- package/dist/requirements/hooks/use-question-options.d.ts.map +1 -0
- package/dist/requirements/hooks/use-question-options.js +9 -0
- package/dist/requirements/hooks/use-transport-requirements.d.ts +30 -0
- package/dist/requirements/hooks/use-transport-requirements.d.ts.map +1 -0
- package/dist/requirements/hooks/use-transport-requirements.js +9 -0
- package/dist/requirements/i18n/en.d.ts +94 -0
- package/dist/requirements/i18n/en.d.ts.map +1 -0
- package/dist/requirements/i18n/en.js +93 -0
- package/dist/requirements/i18n/index.d.ts +5 -0
- package/dist/requirements/i18n/index.d.ts.map +1 -0
- package/dist/requirements/i18n/index.js +3 -0
- package/dist/requirements/i18n/messages.d.ts +59 -0
- package/dist/requirements/i18n/messages.d.ts.map +1 -0
- package/dist/requirements/i18n/messages.js +1 -0
- package/dist/requirements/i18n/provider.d.ts +210 -0
- package/dist/requirements/i18n/provider.d.ts.map +1 -0
- package/dist/requirements/i18n/provider.js +44 -0
- package/dist/requirements/i18n/ro.d.ts +94 -0
- package/dist/requirements/i18n/ro.d.ts.map +1 -0
- package/dist/requirements/i18n/ro.js +93 -0
- package/dist/requirements/index.d.ts +9 -0
- package/dist/requirements/index.d.ts.map +1 -0
- package/dist/requirements/index.js +8 -0
- package/dist/requirements/provider.d.ts +2 -0
- package/dist/requirements/provider.d.ts.map +1 -0
- package/dist/requirements/provider.js +1 -0
- package/dist/requirements/query-keys.d.ts +33 -0
- package/dist/requirements/query-keys.d.ts.map +1 -0
- package/dist/requirements/query-keys.js +13 -0
- package/dist/requirements/query-options.d.ts +371 -0
- package/dist/requirements/query-options.d.ts.map +1 -0
- package/dist/requirements/query-options.js +80 -0
- package/dist/requirements/schemas.d.ts +320 -0
- package/dist/requirements/schemas.d.ts.map +1 -0
- package/dist/requirements/schemas.js +121 -0
- package/dist/requirements/ui.d.ts +4 -0
- package/dist/requirements/ui.d.ts.map +1 -0
- package/dist/requirements/ui.js +3 -0
- package/dist/requirements/utils.d.ts +2 -0
- package/dist/requirements/utils.d.ts.map +1 -0
- package/dist/requirements/utils.js +4 -0
- package/dist/schemas.d.ts +2070 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +507 -0
- package/dist/status-presentation.d.ts +34 -0
- package/dist/status-presentation.d.ts.map +1 -0
- package/dist/status-presentation.js +38 -0
- package/dist/ui.d.ts +43 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +42 -0
- package/package.json +256 -0
- package/src/requirements/styles.css +1 -0
- package/src/styles.css +13 -0
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
// agent-quality: file-size exception -- owner: bookings-react; existing UI surface stays co-located until a dedicated split preserves behavior and tests.
|
|
2
|
+
"use client";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { usePerson, usePersonRelationships, } from "@voyant-travel/relationships-react";
|
|
5
|
+
import { Button, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@voyant-travel/ui/components";
|
|
6
|
+
import { Trash2, UserPlus } from "lucide-react";
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
import { useBookingsUiMessagesOrDefault } from "../i18n/provider.js";
|
|
9
|
+
import { createTravelerFromPerson, RelatedPersonChip, TravelerCategoryButtons, TravelerPersonPicker, TravelerPricingCategorySelect, } from "./travelers-section-controls.js";
|
|
10
|
+
export const emptyTravelerListValue = { travelers: [] };
|
|
11
|
+
function createClientTravelerKey() {
|
|
12
|
+
const random = typeof globalThis.crypto?.randomUUID === "function"
|
|
13
|
+
? globalThis.crypto.randomUUID().replace(/-/g, "")
|
|
14
|
+
: `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;
|
|
15
|
+
return `trav:${random}`;
|
|
16
|
+
}
|
|
17
|
+
/** Factory for a blank row — `role` defaults to `adult` unless the list is empty. */
|
|
18
|
+
export function createBlankTraveler(role = "adult") {
|
|
19
|
+
return {
|
|
20
|
+
clientTravelerKey: createClientTravelerKey(),
|
|
21
|
+
personId: null,
|
|
22
|
+
firstName: "",
|
|
23
|
+
lastName: "",
|
|
24
|
+
email: "",
|
|
25
|
+
phone: "",
|
|
26
|
+
preferredLanguage: "",
|
|
27
|
+
role,
|
|
28
|
+
dateOfBirth: null,
|
|
29
|
+
pricingUnitId: null,
|
|
30
|
+
pricingCategoryId: null,
|
|
31
|
+
inventoryUnitId: null,
|
|
32
|
+
pricingUnitSource: "auto",
|
|
33
|
+
inventoryUnitSource: "auto",
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
// Re-export `computeAgeYears` from the canonical assignment module so
|
|
37
|
+
// existing consumers of `travelers-section`'s public surface keep
|
|
38
|
+
// working. The implementation lives in `@voyant-travel/bookings/pricing-assignment`.
|
|
39
|
+
export { computeAgeYears } from "@voyant-travel/bookings/pricing-assignment";
|
|
40
|
+
import { computeAgeYears as _computeAgeYears, matchUnitByDob as matchAssignmentUnitByDob, matchUnitByRoleHint as matchAssignmentUnitByRoleHint, } from "@voyant-travel/bookings/pricing-assignment";
|
|
41
|
+
/**
|
|
42
|
+
* Derive the age-banded traveler role from DOB. Falls back to `adult`
|
|
43
|
+
* when DOB is missing so partial entries still typecheck downstream.
|
|
44
|
+
*
|
|
45
|
+
* Thresholds:
|
|
46
|
+
* - infant: < 2
|
|
47
|
+
* - child: 2 – 17
|
|
48
|
+
* - adult: 18+
|
|
49
|
+
*/
|
|
50
|
+
export function deriveTravelerRoleFromDob(dob) {
|
|
51
|
+
const age = _computeAgeYears(dob);
|
|
52
|
+
if (age == null)
|
|
53
|
+
return "adult";
|
|
54
|
+
if (age < 2)
|
|
55
|
+
return "infant";
|
|
56
|
+
if (age < 18)
|
|
57
|
+
return "child";
|
|
58
|
+
return "adult";
|
|
59
|
+
}
|
|
60
|
+
function roleFromPricingCategoryType(categoryType) {
|
|
61
|
+
if (categoryType === "child")
|
|
62
|
+
return "child";
|
|
63
|
+
if (categoryType === "infant")
|
|
64
|
+
return "infant";
|
|
65
|
+
return "adult";
|
|
66
|
+
}
|
|
67
|
+
export function categoryMatchesDob(category, dob) {
|
|
68
|
+
if (category.minAge == null && category.maxAge == null)
|
|
69
|
+
return false;
|
|
70
|
+
const age = _computeAgeYears(dob);
|
|
71
|
+
if (age == null)
|
|
72
|
+
return false;
|
|
73
|
+
return ((category.minAge == null || age >= category.minAge) &&
|
|
74
|
+
(category.maxAge == null || age <= category.maxAge));
|
|
75
|
+
}
|
|
76
|
+
function categoryMatchesRole(category, role) {
|
|
77
|
+
if (role === "lead" || role === "adult")
|
|
78
|
+
return category.categoryType === "adult";
|
|
79
|
+
if (role === "child")
|
|
80
|
+
return category.categoryType === "child";
|
|
81
|
+
if (role === "infant")
|
|
82
|
+
return category.categoryType === "infant";
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
export function matchPricingCategoryForTraveler(categories, dob, role, inventoryUnitId) {
|
|
86
|
+
if (!categories || categories.length === 0)
|
|
87
|
+
return null;
|
|
88
|
+
const pool = inventoryUnitId
|
|
89
|
+
? categories.filter((category) => category.unitIds.includes(inventoryUnitId))
|
|
90
|
+
: categories;
|
|
91
|
+
if (pool.length === 0)
|
|
92
|
+
return null;
|
|
93
|
+
return (pool.find((category) => categoryMatchesDob(category, dob))?.categoryId ??
|
|
94
|
+
pool.find((category) => categoryMatchesRole(category, role))?.categoryId ??
|
|
95
|
+
pool[0]?.categoryId ??
|
|
96
|
+
null);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Adapter from this file's `RoomGroupUnit` shape (UI-side, uses
|
|
100
|
+
* `unitId`) to the canonical `PricingAssignmentUnit` shape (uses
|
|
101
|
+
* `optionUnitId`). Phase 1 of voyant-travel/voyant#1267 will collapse these
|
|
102
|
+
* by renaming the UI shape.
|
|
103
|
+
*/
|
|
104
|
+
function roomGroupUnitsAsAssignmentUnits(units) {
|
|
105
|
+
return units.map((u) => ({
|
|
106
|
+
optionId: null,
|
|
107
|
+
optionUnitId: u.unitId,
|
|
108
|
+
unitName: u.unitName,
|
|
109
|
+
unitCode: u.unitCode,
|
|
110
|
+
minAge: u.minAge,
|
|
111
|
+
maxAge: u.maxAge,
|
|
112
|
+
unitType: u.unitType,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
function matchUnitByDob(units, dob) {
|
|
116
|
+
return matchAssignmentUnitByDob(roomGroupUnitsAsAssignmentUnits(units), dob);
|
|
117
|
+
}
|
|
118
|
+
function matchUnitByRoleHint(units, role) {
|
|
119
|
+
return matchAssignmentUnitByRoleHint(roomGroupUnitsAsAssignmentUnits(units), role);
|
|
120
|
+
}
|
|
121
|
+
const NO_ROOM = "__unassigned__";
|
|
122
|
+
/**
|
|
123
|
+
* Traveler list for booking-create flows. Each row can point at an existing
|
|
124
|
+
* CRM person, create a new CRM person, or carry manual name/email details,
|
|
125
|
+
* plus role and optional room assignment.
|
|
126
|
+
*
|
|
127
|
+
* ### Parent contract
|
|
128
|
+
*
|
|
129
|
+
* At submit time, the parent:
|
|
130
|
+
* 1. Inserts a `booking_travelers` row per traveler with `participantType`
|
|
131
|
+
* derived from the role (`lead` / `adult` → traveler; `child` / `infant`
|
|
132
|
+
* → traveler with travelerCategory set).
|
|
133
|
+
* 2. Carries `personId` through when the traveler is tied to CRM, including
|
|
134
|
+
* when the payer is also traveling.
|
|
135
|
+
* 3. Exactly one row should have `role: "lead"` — enforced at submit, not
|
|
136
|
+
* here. The UI lets the operator pick whichever layout they want, then
|
|
137
|
+
* the submit handler errors if the invariant isn't met.
|
|
138
|
+
*/
|
|
139
|
+
export function TravelersSection({ value, onChange, roomUnits, roomGroups, pricingCategories, billingPersonId, labels, }) {
|
|
140
|
+
const messages = useBookingsUiMessagesOrDefault();
|
|
141
|
+
const merged = { ...messages.travelersSection.labels, ...labels };
|
|
142
|
+
const billingPerson = usePerson(billingPersonId ?? undefined, {
|
|
143
|
+
enabled: Boolean(billingPersonId),
|
|
144
|
+
});
|
|
145
|
+
const updateAt = (index, patch) => {
|
|
146
|
+
const next = value.travelers.map((traveler, i) => i === index ? { ...traveler, ...patch } : traveler);
|
|
147
|
+
onChange({ travelers: next });
|
|
148
|
+
};
|
|
149
|
+
const removeAt = (index) => {
|
|
150
|
+
onChange({ travelers: value.travelers.filter((_, i) => i !== index) });
|
|
151
|
+
};
|
|
152
|
+
const pickPricingUnitIdForTraveler = React.useCallback((dateOfBirth = null, role = null, preferredUnitId = null) => {
|
|
153
|
+
if (!roomGroups || roomGroups.length === 0)
|
|
154
|
+
return null;
|
|
155
|
+
const group = (preferredUnitId
|
|
156
|
+
? roomGroups.find((g) => g.primaryUnitId === preferredUnitId ||
|
|
157
|
+
g.units.some((u) => u.unitId === preferredUnitId))
|
|
158
|
+
: undefined) ?? roomGroups[0];
|
|
159
|
+
if (!group)
|
|
160
|
+
return null;
|
|
161
|
+
return (matchUnitByDob(group.units, dateOfBirth) ??
|
|
162
|
+
matchUnitByRoleHint(group.units, role) ??
|
|
163
|
+
group.units.find((unit) => unit.unitType == null || unit.unitType === "person")?.unitId ??
|
|
164
|
+
null);
|
|
165
|
+
}, [roomGroups]);
|
|
166
|
+
// Auto-pick a room with seats available so operators don't have to
|
|
167
|
+
// hunt for the dropdown on every traveler — they can still override
|
|
168
|
+
// manually via the Room select. Pricing is picked from the same
|
|
169
|
+
// option when the product exposes person tiers.
|
|
170
|
+
const pickAssignmentsForNewTraveler = React.useCallback((dateOfBirth = null, role = null) => {
|
|
171
|
+
if (!roomUnits || roomUnits.length === 0) {
|
|
172
|
+
return {
|
|
173
|
+
pricingUnitId: null,
|
|
174
|
+
pricingCategoryId: matchPricingCategoryForTraveler(pricingCategories, dateOfBirth, role, null),
|
|
175
|
+
inventoryUnitId: null,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const pickedRoom = roomUnits.find((unit) => unit.remainingCapacity > 0)?.unitId ?? null;
|
|
179
|
+
if (!pickedRoom || !roomGroups || roomGroups.length === 0) {
|
|
180
|
+
return {
|
|
181
|
+
pricingUnitId: null,
|
|
182
|
+
pricingCategoryId: matchPricingCategoryForTraveler(pricingCategories, dateOfBirth, role, pickedRoom),
|
|
183
|
+
inventoryUnitId: pickedRoom,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const pricingUnitId = pickPricingUnitIdForTraveler(dateOfBirth, role, pickedRoom);
|
|
187
|
+
return {
|
|
188
|
+
pricingUnitId,
|
|
189
|
+
pricingCategoryId: matchPricingCategoryForTraveler(pricingCategories, dateOfBirth, role, pickedRoom),
|
|
190
|
+
inventoryUnitId: pickedRoom,
|
|
191
|
+
};
|
|
192
|
+
}, [roomUnits, roomGroups, pricingCategories, pickPricingUnitIdForTraveler]);
|
|
193
|
+
// Note: there is no hydration effect any more. Travelers attached
|
|
194
|
+
// before the option-units queries resolve get null assignment ids
|
|
195
|
+
// and `*UnitSource: "auto"`; the resolver in
|
|
196
|
+
// `@voyant-travel/bookings/pricing-assignment` re-derives them at every
|
|
197
|
+
// preview/submit pass, and respects `"none"` (explicit No room) /
|
|
198
|
+
// `"manual"` (operator click) when set. Operator intent is now
|
|
199
|
+
// declarative on the row, not implicit in a one-shot effect.
|
|
200
|
+
const addRow = () => {
|
|
201
|
+
// First traveler defaults to `lead` so the operator doesn't have to
|
|
202
|
+
// remember to flip the role on the initial row.
|
|
203
|
+
const role = value.travelers.length === 0 ? "lead" : "adult";
|
|
204
|
+
const blank = createBlankTraveler(role);
|
|
205
|
+
onChange({
|
|
206
|
+
travelers: [
|
|
207
|
+
...value.travelers,
|
|
208
|
+
{
|
|
209
|
+
...blank,
|
|
210
|
+
...pickAssignmentsForNewTraveler(null, role),
|
|
211
|
+
pricingUnitSource: "auto",
|
|
212
|
+
inventoryUnitSource: "auto",
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
});
|
|
216
|
+
};
|
|
217
|
+
const addBillingPerson = () => {
|
|
218
|
+
if (!billingPerson.data)
|
|
219
|
+
return;
|
|
220
|
+
const role = value.travelers.length === 0 ? "lead" : "adult";
|
|
221
|
+
const traveler = createTravelerFromPerson(billingPerson.data, role);
|
|
222
|
+
onChange({
|
|
223
|
+
travelers: [
|
|
224
|
+
...value.travelers,
|
|
225
|
+
{
|
|
226
|
+
...traveler,
|
|
227
|
+
...pickAssignmentsForNewTraveler(traveler.dateOfBirth, role),
|
|
228
|
+
pricingUnitSource: "auto",
|
|
229
|
+
inventoryUnitSource: "auto",
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
});
|
|
233
|
+
};
|
|
234
|
+
const addRelatedPersonTraveler = (person) => {
|
|
235
|
+
const role = value.travelers.length === 0 ? "lead" : "adult";
|
|
236
|
+
const traveler = createTravelerFromPerson(person, role);
|
|
237
|
+
onChange({
|
|
238
|
+
travelers: [
|
|
239
|
+
...value.travelers,
|
|
240
|
+
{
|
|
241
|
+
...traveler,
|
|
242
|
+
...pickAssignmentsForNewTraveler(traveler.dateOfBirth, role),
|
|
243
|
+
pricingUnitSource: "auto",
|
|
244
|
+
inventoryUnitSource: "auto",
|
|
245
|
+
},
|
|
246
|
+
],
|
|
247
|
+
});
|
|
248
|
+
};
|
|
249
|
+
const hasBillingPersonTraveler = Boolean(billingPersonId && value.travelers.some((traveler) => traveler.personId === billingPersonId));
|
|
250
|
+
// Relationships of the billing person — surfaced as one-click "add as
|
|
251
|
+
// traveler" chips so the operator can populate family/companions
|
|
252
|
+
// without searching for them in the picker.
|
|
253
|
+
const relationshipsQuery = usePersonRelationships(billingPersonId ?? undefined, {
|
|
254
|
+
enabled: Boolean(billingPersonId),
|
|
255
|
+
});
|
|
256
|
+
const alreadyAddedIds = React.useMemo(() => new Set(value.travelers.map((t) => t.personId).filter(Boolean)), [value.travelers]);
|
|
257
|
+
const relatedPersonIds = React.useMemo(() => {
|
|
258
|
+
if (!billingPersonId)
|
|
259
|
+
return [];
|
|
260
|
+
const seen = new Set();
|
|
261
|
+
const out = [];
|
|
262
|
+
for (const rel of relationshipsQuery.data?.data ?? []) {
|
|
263
|
+
const otherId = rel.fromPersonId === billingPersonId ? rel.toPersonId : rel.fromPersonId;
|
|
264
|
+
if (seen.has(otherId) || alreadyAddedIds.has(otherId))
|
|
265
|
+
continue;
|
|
266
|
+
seen.add(otherId);
|
|
267
|
+
out.push({ id: otherId, kind: rel.kind });
|
|
268
|
+
}
|
|
269
|
+
return out;
|
|
270
|
+
}, [billingPersonId, relationshipsQuery.data?.data, alreadyAddedIds]);
|
|
271
|
+
// base-ui's Select reads labels via the `items` prop — without it,
|
|
272
|
+
// <SelectValue /> falls back to the raw value (the unit id). Memoize
|
|
273
|
+
// once for all rows so identity is stable across renders.
|
|
274
|
+
const roomSelectItems = React.useMemo(() => [
|
|
275
|
+
{ label: merged.noRoom, value: NO_ROOM },
|
|
276
|
+
...(roomUnits ?? []).map((unit) => ({ label: unit.unitName, value: unit.unitId })),
|
|
277
|
+
], [roomUnits, merged.noRoom]);
|
|
278
|
+
return (_jsxs("div", { className: "flex flex-col gap-2 rounded-md border p-3", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, { children: merged.heading }), _jsx(Button, { type: "button", size: "sm", variant: "ghost", onClick: addRow, children: merged.addTraveler })] }), billingPersonId && !hasBillingPersonTraveler ? (_jsx("div", { children: _jsxs(Button, { type: "button", size: "sm", variant: "outline", onClick: addBillingPerson, disabled: !billingPerson.data, children: [_jsx(UserPlus, { className: "mr-1 h-3.5 w-3.5" }), merged.addBillingPerson] }) })) : null, relatedPersonIds.length > 0 ? (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsx("span", { className: "text-xs text-muted-foreground", children: merged.relatedPeopleHeading }), _jsx("div", { className: "flex flex-wrap gap-1.5", children: relatedPersonIds.map((rel) => (_jsx(RelatedPersonChip, { personId: rel.id, kind: rel.kind, addLabel: merged.addRelatedPerson, onAdd: addRelatedPersonTraveler }, rel.id))) })] })) : null, value.travelers.length === 0 ? (_jsx("p", { className: "text-xs text-muted-foreground", children: merged.empty })) : (_jsx("div", { className: "flex flex-col gap-2", children: value.travelers.map((traveler, index) => (_jsxs("div", { className: "flex flex-col gap-2 rounded-md border p-2", children: [_jsx(TravelerPersonPicker, { personId: traveler.personId, labels: merged, pinnedPeople: billingPerson.data ? [billingPerson.data] : [], onSelect: (person) => updateAt(index, {
|
|
279
|
+
personId: person.id,
|
|
280
|
+
firstName: person.firstName,
|
|
281
|
+
lastName: person.lastName,
|
|
282
|
+
email: person.email ?? "",
|
|
283
|
+
phone: person.phone ?? "",
|
|
284
|
+
preferredLanguage: person.preferredLanguage ?? "",
|
|
285
|
+
dateOfBirth: person.dateOfBirth ?? null,
|
|
286
|
+
// Re-derive auto-owned unit assignments when the
|
|
287
|
+
// linked CRM person changes. Pricing and inventory
|
|
288
|
+
// stay independent: a manual room does not freeze
|
|
289
|
+
// DOB-driven pricing, and a manual category does
|
|
290
|
+
// not move the room.
|
|
291
|
+
...(traveler.pricingUnitSource === "manual" ||
|
|
292
|
+
traveler.pricingUnitSource === "none"
|
|
293
|
+
? {}
|
|
294
|
+
: {
|
|
295
|
+
pricingUnitId: pickPricingUnitIdForTraveler(person.dateOfBirth ?? null, traveler.role, traveler.inventoryUnitId),
|
|
296
|
+
pricingUnitSource: "auto",
|
|
297
|
+
}),
|
|
298
|
+
pricingCategoryId: matchPricingCategoryForTraveler(pricingCategories, person.dateOfBirth ?? null, traveler.role, traveler.inventoryUnitId),
|
|
299
|
+
...(traveler.inventoryUnitSource === "manual" ||
|
|
300
|
+
traveler.inventoryUnitSource === "none"
|
|
301
|
+
? {}
|
|
302
|
+
: {
|
|
303
|
+
inventoryUnitId: pickAssignmentsForNewTraveler(person.dateOfBirth ?? null, traveler.role).inventoryUnitId,
|
|
304
|
+
inventoryUnitSource: "auto",
|
|
305
|
+
}),
|
|
306
|
+
}), onClear: () => updateAt(index, {
|
|
307
|
+
personId: null,
|
|
308
|
+
firstName: "",
|
|
309
|
+
lastName: "",
|
|
310
|
+
email: "",
|
|
311
|
+
phone: "",
|
|
312
|
+
preferredLanguage: "",
|
|
313
|
+
dateOfBirth: null,
|
|
314
|
+
...(traveler.pricingUnitSource === "manual" ||
|
|
315
|
+
traveler.pricingUnitSource === "none"
|
|
316
|
+
? {}
|
|
317
|
+
: {
|
|
318
|
+
pricingUnitId: pickPricingUnitIdForTraveler(null, traveler.role, traveler.inventoryUnitId),
|
|
319
|
+
pricingUnitSource: "auto",
|
|
320
|
+
}),
|
|
321
|
+
pricingCategoryId: matchPricingCategoryForTraveler(pricingCategories, null, traveler.role, traveler.inventoryUnitId),
|
|
322
|
+
...(traveler.inventoryUnitSource === "manual" ||
|
|
323
|
+
traveler.inventoryUnitSource === "none"
|
|
324
|
+
? {}
|
|
325
|
+
: {
|
|
326
|
+
inventoryUnitId: pickAssignmentsForNewTraveler(null, traveler.role)
|
|
327
|
+
.inventoryUnitId,
|
|
328
|
+
inventoryUnitSource: "auto",
|
|
329
|
+
}),
|
|
330
|
+
}) }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [pricingCategories ? (_jsx(TravelerPricingCategorySelect, { traveler: traveler, categories: pricingCategories, label: merged.category, onPickCategory: (category) => updateAt(index, {
|
|
331
|
+
pricingCategoryId: category.categoryId,
|
|
332
|
+
role: traveler.role === "lead" &&
|
|
333
|
+
roleFromPricingCategoryType(category.categoryType) === "adult"
|
|
334
|
+
? "lead"
|
|
335
|
+
: roleFromPricingCategoryType(category.categoryType),
|
|
336
|
+
}) })) : (_jsx(TravelerCategoryButtons, { traveler: traveler, roomGroups: roomGroups, fallbackLabels: {
|
|
337
|
+
category: merged.category,
|
|
338
|
+
adult: merged.roleAdult,
|
|
339
|
+
child: merged.roleChild,
|
|
340
|
+
infant: merged.roleInfant,
|
|
341
|
+
}, onPickUnit: (unitId, nextRole, source) => updateAt(index, {
|
|
342
|
+
pricingUnitId: unitId,
|
|
343
|
+
role: nextRole,
|
|
344
|
+
// Only freeze as manual when the dynamic button
|
|
345
|
+
// actually picked a unit. Role-only clicks via
|
|
346
|
+
// the static fallback stay `auto` so the
|
|
347
|
+
// resolver can re-derive once real units load.
|
|
348
|
+
pricingUnitSource: source,
|
|
349
|
+
}) })), roomUnits && roomUnits.length > 0 ? (_jsxs("div", { className: "flex flex-col gap-1", children: [_jsx(Label, { className: "text-xs", children: merged.room }), _jsxs(Select, { items: roomSelectItems, value: traveler.inventoryUnitId ?? NO_ROOM, onValueChange: (v) => updateAt(index, {
|
|
350
|
+
inventoryUnitId: v === NO_ROOM || !v ? null : v,
|
|
351
|
+
inventoryUnitSource: v === NO_ROOM || !v ? "none" : "manual",
|
|
352
|
+
pricingCategoryId: matchPricingCategoryForTraveler(pricingCategories, traveler.dateOfBirth, traveler.role, v === NO_ROOM || !v ? null : v),
|
|
353
|
+
}), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: NO_ROOM, children: merged.noRoom }), roomUnits.map((unit) => (_jsx(SelectItem, { value: unit.unitId, disabled: unit.remainingCapacity <= 0 &&
|
|
354
|
+
traveler.inventoryUnitId !== unit.unitId, children: unit.unitName }, unit.unitId)))] })] })] })) : null] }), _jsx("div", { className: "flex justify-end", children: _jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "h-7 text-destructive", onClick: () => removeAt(index), "aria-label": merged.remove, children: [_jsx(Trash2, { className: "mr-1 h-3.5 w-3.5" }), merged.remove] }) })] }, index))) }))] }));
|
|
355
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** Details of a successfully-validated voucher. */
|
|
2
|
+
export interface PickedVoucher {
|
|
3
|
+
id: string;
|
|
4
|
+
code: string;
|
|
5
|
+
label: string | null;
|
|
6
|
+
currency: string | null;
|
|
7
|
+
remainingAmountCents: number | null;
|
|
8
|
+
expiresAt: string | null;
|
|
9
|
+
}
|
|
10
|
+
export interface VoucherPickerValue {
|
|
11
|
+
/** Code typed by the operator. Not cleared on failure so they can correct a typo. */
|
|
12
|
+
code: string;
|
|
13
|
+
/** Populated only when the last validate call succeeded. */
|
|
14
|
+
picked: PickedVoucher | null;
|
|
15
|
+
/** Reason returned by the server when validate fails, or a client-side message. */
|
|
16
|
+
error: string | null;
|
|
17
|
+
}
|
|
18
|
+
export declare const emptyVoucherPickerValue: VoucherPickerValue;
|
|
19
|
+
export interface VoucherPickerSectionProps {
|
|
20
|
+
value: VoucherPickerValue;
|
|
21
|
+
onChange: (value: VoucherPickerValue) => void;
|
|
22
|
+
/**
|
|
23
|
+
* Context for the validate call — when provided, the server rejects vouchers
|
|
24
|
+
* locked to a different booking / mismatched currency / insufficient balance.
|
|
25
|
+
*/
|
|
26
|
+
bookingId?: string;
|
|
27
|
+
currency?: string;
|
|
28
|
+
amountCents?: number;
|
|
29
|
+
labels?: {
|
|
30
|
+
heading?: string;
|
|
31
|
+
codePlaceholder?: string;
|
|
32
|
+
apply?: string;
|
|
33
|
+
clear?: string;
|
|
34
|
+
remainingLabel?: string;
|
|
35
|
+
invalidLabel?: string;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Voucher picker for booking-create flows. Operator enters a code, clicks
|
|
40
|
+
* Apply, and the server-side `/v1/public/vouchers/validate` runs all the
|
|
41
|
+
* usual guards (status, expiry, currency, booking-assignment, balance).
|
|
42
|
+
*
|
|
43
|
+
* The section only *validates* — it doesn't redeem. Redemption happens when
|
|
44
|
+
* the parent calls `POST /v1/finance/vouchers/:id/redeem` at submit time,
|
|
45
|
+
* after the booking exists and the final amount is known. Validate being
|
|
46
|
+
* idempotent means the operator can try a code, correct a typo, and try
|
|
47
|
+
* again without leaving a trail.
|
|
48
|
+
*/
|
|
49
|
+
export declare function VoucherPickerSection({ value, onChange, bookingId, currency, amountCents, labels, }: VoucherPickerSectionProps): import("react/jsx-runtime").JSX.Element;
|
|
50
|
+
//# sourceMappingURL=voucher-picker-section.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voucher-picker-section.d.ts","sourceRoot":"","sources":["../../src/components/voucher-picker-section.tsx"],"names":[],"mappings":"AAOA,mDAAmD;AACnD,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,qFAAqF;IACrF,IAAI,EAAE,MAAM,CAAA;IACZ,4DAA4D;IAC5D,MAAM,EAAE,aAAa,GAAG,IAAI,CAAA;IAC5B,mFAAmF;IACnF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB;AAED,eAAO,MAAM,uBAAuB,EAAE,kBAIrC,CAAA;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,kBAAkB,CAAA;IACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAA;IAC7C;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,eAAe,CAAC,EAAE,MAAM,CAAA;QACxB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,YAAY,CAAC,EAAE,MAAM,CAAA;KACtB,CAAA;CACF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,KAAK,EACL,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,WAAW,EACX,MAAM,GACP,EAAE,yBAAyB,2CAiH3B"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { usePublicVoucherValidationMutation } from "@voyant-travel/finance-react";
|
|
4
|
+
import { Button, Input, Label } from "@voyant-travel/ui/components";
|
|
5
|
+
import { CheckCircle2, Loader2, XCircle } from "lucide-react";
|
|
6
|
+
import { useBookingsUiI18nOrDefault, useBookingsUiMessagesOrDefault } from "../i18n/provider.js";
|
|
7
|
+
export const emptyVoucherPickerValue = {
|
|
8
|
+
code: "",
|
|
9
|
+
picked: null,
|
|
10
|
+
error: null,
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Voucher picker for booking-create flows. Operator enters a code, clicks
|
|
14
|
+
* Apply, and the server-side `/v1/public/vouchers/validate` runs all the
|
|
15
|
+
* usual guards (status, expiry, currency, booking-assignment, balance).
|
|
16
|
+
*
|
|
17
|
+
* The section only *validates* — it doesn't redeem. Redemption happens when
|
|
18
|
+
* the parent calls `POST /v1/finance/vouchers/:id/redeem` at submit time,
|
|
19
|
+
* after the booking exists and the final amount is known. Validate being
|
|
20
|
+
* idempotent means the operator can try a code, correct a typo, and try
|
|
21
|
+
* again without leaving a trail.
|
|
22
|
+
*/
|
|
23
|
+
export function VoucherPickerSection({ value, onChange, bookingId, currency, amountCents, labels, }) {
|
|
24
|
+
const { formatCurrency } = useBookingsUiI18nOrDefault();
|
|
25
|
+
const messages = useBookingsUiMessagesOrDefault();
|
|
26
|
+
const merged = { ...messages.voucherPickerSection.labels, ...labels };
|
|
27
|
+
const validate = usePublicVoucherValidationMutation();
|
|
28
|
+
const handleApply = async () => {
|
|
29
|
+
const code = value.code.trim();
|
|
30
|
+
if (!code)
|
|
31
|
+
return;
|
|
32
|
+
try {
|
|
33
|
+
const { data } = await validate.mutateAsync({
|
|
34
|
+
code,
|
|
35
|
+
bookingId: bookingId ?? undefined,
|
|
36
|
+
currency: currency ?? undefined,
|
|
37
|
+
amountCents: amountCents ?? undefined,
|
|
38
|
+
});
|
|
39
|
+
if (data.valid && data.voucher) {
|
|
40
|
+
onChange({
|
|
41
|
+
code,
|
|
42
|
+
picked: {
|
|
43
|
+
id: data.voucher.id,
|
|
44
|
+
code: data.voucher.code,
|
|
45
|
+
label: data.voucher.label,
|
|
46
|
+
currency: data.voucher.currency,
|
|
47
|
+
remainingAmountCents: data.voucher.remainingAmountCents,
|
|
48
|
+
expiresAt: data.voucher.expiresAt,
|
|
49
|
+
},
|
|
50
|
+
error: null,
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
onChange({
|
|
55
|
+
code,
|
|
56
|
+
picked: null,
|
|
57
|
+
error: messages.voucherPickerSection.reasonMessages[data.reason] ?? messages.voucherPickerSection.validation.invalid,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
onChange({
|
|
62
|
+
code,
|
|
63
|
+
picked: null,
|
|
64
|
+
error: err instanceof Error
|
|
65
|
+
? err.message
|
|
66
|
+
: messages.voucherPickerSection.validation.lookupFailed,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const handleClear = () => onChange(emptyVoucherPickerValue);
|
|
71
|
+
return (_jsxs("div", { className: "flex flex-col gap-2 rounded-md border p-3", children: [_jsx(Label, { children: merged.heading }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Input, { value: value.code, onChange: (e) => onChange({ ...value, code: e.target.value, error: null }), onKeyDown: (e) => {
|
|
72
|
+
if (e.key === "Enter") {
|
|
73
|
+
e.preventDefault();
|
|
74
|
+
void handleApply();
|
|
75
|
+
}
|
|
76
|
+
}, placeholder: merged.codePlaceholder, disabled: validate.isPending || Boolean(value.picked) }), value.picked ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: handleClear, children: merged.clear })) : (_jsxs(Button, { type: "button", size: "sm", onClick: () => void handleApply(), disabled: validate.isPending || !value.code.trim(), children: [validate.isPending && _jsx(Loader2, { className: "mr-1 h-3.5 w-3.5 animate-spin" }), merged.apply] }))] }), value.picked && (_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-emerald-600" }), _jsxs("span", { children: [merged.remainingLabel, " ", _jsx("strong", { children: value.picked.remainingAmountCents == null || !value.picked.currency
|
|
77
|
+
? messages.voucherPickerSection.validation.amountUnavailable
|
|
78
|
+
: formatCurrency(value.picked.remainingAmountCents / 100, value.picked.currency) })] })] })), value.error && (_jsxs("div", { className: "flex items-start gap-2 text-sm text-destructive", children: [_jsx(XCircle, { className: "mt-0.5 h-4 w-4" }), _jsxs("span", { children: [merged.invalidLabel, " ", value.error] })] }))] }));
|
|
79
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
export type VoyantFetcher = (url: string, init?: RequestInit) => Promise<Response>;
|
|
3
|
+
export declare const defaultFetcher: VoyantFetcher;
|
|
4
|
+
export declare class VoyantApiError extends Error {
|
|
5
|
+
readonly status: number;
|
|
6
|
+
readonly body: unknown;
|
|
7
|
+
constructor(message: string, status: number, body: unknown);
|
|
8
|
+
}
|
|
9
|
+
export interface FetchWithValidationOptions {
|
|
10
|
+
baseUrl: string;
|
|
11
|
+
fetcher: VoyantFetcher;
|
|
12
|
+
}
|
|
13
|
+
export declare function fetchWithValidation<TOut>(path: string, schema: z.ZodType<TOut>, options: FetchWithValidationOptions, init?: RequestInit): Promise<TOut>;
|
|
14
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/extras/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAE5B,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;AAElF,eAAO,MAAM,cAAc,EAAE,aACoB,CAAA;AAEjD,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;gBAEV,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO;CAM3D;AAaD,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,aAAa,CAAA;CACvB;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAC5C,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EACvB,OAAO,EAAE,0BAA0B,EACnC,IAAI,CAAC,EAAE,WAAW,GACjB,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export const defaultFetcher = (url, init) => fetch(url, { credentials: "include", ...init });
|
|
2
|
+
export class VoyantApiError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
body;
|
|
5
|
+
constructor(message, status, body) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "VoyantApiError";
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.body = body;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function extractErrorMessage(status, statusText, body) {
|
|
13
|
+
if (typeof body === "object" && body !== null && "error" in body) {
|
|
14
|
+
const err = body.error;
|
|
15
|
+
if (typeof err === "string")
|
|
16
|
+
return err;
|
|
17
|
+
if (typeof err === "object" && err !== null && "message" in err) {
|
|
18
|
+
return String(err.message);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return `Voyant API error: ${status} ${statusText}`;
|
|
22
|
+
}
|
|
23
|
+
export async function fetchWithValidation(path, schema, options, init) {
|
|
24
|
+
const url = joinUrl(options.baseUrl, path);
|
|
25
|
+
const headers = new Headers(init?.headers);
|
|
26
|
+
if (init?.body !== undefined && !headers.has("Content-Type")) {
|
|
27
|
+
headers.set("Content-Type", "application/json");
|
|
28
|
+
}
|
|
29
|
+
const response = await options.fetcher(url, { ...init, headers });
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
const body = await safeJson(response);
|
|
32
|
+
throw new VoyantApiError(extractErrorMessage(response.status, response.statusText, body), response.status, body);
|
|
33
|
+
}
|
|
34
|
+
if (response.status === 204)
|
|
35
|
+
return schema.parse(undefined);
|
|
36
|
+
const body = await safeJson(response);
|
|
37
|
+
const parsed = schema.safeParse(body);
|
|
38
|
+
if (!parsed.success) {
|
|
39
|
+
throw new VoyantApiError(`Voyant API response failed validation: ${parsed.error.message}`, response.status, body);
|
|
40
|
+
}
|
|
41
|
+
return parsed.data;
|
|
42
|
+
}
|
|
43
|
+
async function safeJson(response) {
|
|
44
|
+
const text = await response.text();
|
|
45
|
+
if (!text)
|
|
46
|
+
return undefined;
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(text);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return text;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function joinUrl(baseUrl, path) {
|
|
55
|
+
const trimmedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
56
|
+
const trimmedPath = path.startsWith("/") ? path : `/${path}`;
|
|
57
|
+
return `${trimmedBase}${trimmedPath}`;
|
|
58
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CatalogSearchHit } from "@voyant-travel/catalog-react";
|
|
2
|
+
export interface ExtraCatalogCardProps {
|
|
3
|
+
hit: CatalogSearchHit;
|
|
4
|
+
onClick?: (hit: CatalogSearchHit) => void;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Search-result card for an extras hit (sub-line-item add-ons attached
|
|
9
|
+
* to bookings). Reads: `name`, `category`, `priceCents`, `currency`,
|
|
10
|
+
* `unit` (per_person | per_booking | per_night), `tags`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function ExtraCatalogCard({ hit, onClick, className }: ExtraCatalogCardProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
//# sourceMappingURL=extra-catalog-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extra-catalog-card.d.ts","sourceRoot":"","sources":["../../../src/extras/components/extra-catalog-card.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAMpE,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,gBAAgB,CAAA;IACrB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,IAAI,CAAA;IACzC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,qBAAqB,2CA8DlF"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Badge } from "@voyant-travel/ui/components/badge";
|
|
4
|
+
import { Card, CardContent } from "@voyant-travel/ui/components/card";
|
|
5
|
+
import { cn } from "@voyant-travel/ui/lib/utils";
|
|
6
|
+
import { useExtrasUiI18nOrDefault } from "../i18n/index.js";
|
|
7
|
+
/**
|
|
8
|
+
* Search-result card for an extras hit (sub-line-item add-ons attached
|
|
9
|
+
* to bookings). Reads: `name`, `category`, `priceCents`, `currency`,
|
|
10
|
+
* `unit` (per_person | per_booking | per_night), `tags`.
|
|
11
|
+
*/
|
|
12
|
+
export function ExtraCatalogCard({ hit, onClick, className }) {
|
|
13
|
+
const i18n = useExtrasUiI18nOrDefault();
|
|
14
|
+
const messages = i18n.messages.catalogCard;
|
|
15
|
+
const f = hit.document.fields;
|
|
16
|
+
const name = stringOr(f.name, messages.untitled);
|
|
17
|
+
const category = stringOr(f.category, null);
|
|
18
|
+
const unit = stringOr(f.unit, null);
|
|
19
|
+
const status = stringOr(f.status, null);
|
|
20
|
+
const tags = stringArray(f.tags);
|
|
21
|
+
const price = numberOr(f.priceCents, null);
|
|
22
|
+
const currency = stringOr(f.currency ?? f.sellCurrency, null);
|
|
23
|
+
const priceLabel = price != null && currency
|
|
24
|
+
? i18n.formatCurrency(price / 100, currency, {
|
|
25
|
+
maximumFractionDigits: 2,
|
|
26
|
+
})
|
|
27
|
+
: null;
|
|
28
|
+
return (_jsx(Card, { className: cn("h-full cursor-pointer transition-colors hover:border-primary/40", onClick == null && "cursor-default", className), onClick: onClick ? () => onClick(hit) : undefined, children: _jsxs(CardContent, { className: "flex h-full flex-col gap-2 p-4", children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsx("h3", { className: "line-clamp-2 font-medium text-sm", children: name }), status && (_jsx(Badge, { variant: status === "active" ? "default" : "secondary", className: "shrink-0", children: status }))] }), _jsxs("div", { className: "flex flex-wrap items-center gap-2 text-muted-foreground text-xs", children: [category && _jsx("span", { children: category }), priceLabel && (_jsxs("span", { className: "ml-auto font-medium text-foreground", children: [priceLabel, unit && (_jsx("span", { className: "ml-1 text-muted-foreground", children: formatTemplate(messages.unitPrefix, { unit: unit.replace(/_/g, " ") }) }))] }))] }), tags.length > 0 && (_jsx("div", { className: "mt-auto flex flex-wrap gap-1", children: tags.slice(0, 4).map((tag) => (_jsx(Badge, { variant: "outline", className: "text-[10px]", children: tag }, tag))) }))] }) }));
|
|
29
|
+
}
|
|
30
|
+
function formatTemplate(template, values) {
|
|
31
|
+
return template.replace(/\{(\w+)\}/g, (_, key) => {
|
|
32
|
+
const value = values[key];
|
|
33
|
+
return value === undefined ? "" : String(value);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function stringOr(value, fallback) {
|
|
37
|
+
return typeof value === "string" && value.length > 0 ? value : fallback;
|
|
38
|
+
}
|
|
39
|
+
function numberOr(value, fallback) {
|
|
40
|
+
if (typeof value === "number")
|
|
41
|
+
return value;
|
|
42
|
+
if (typeof value === "string") {
|
|
43
|
+
const n = Number(value);
|
|
44
|
+
return Number.isFinite(n) ? n : fallback;
|
|
45
|
+
}
|
|
46
|
+
return fallback;
|
|
47
|
+
}
|
|
48
|
+
function stringArray(value) {
|
|
49
|
+
if (!Array.isArray(value))
|
|
50
|
+
return [];
|
|
51
|
+
return value.filter((v) => typeof v === "string" && v.length > 0);
|
|
52
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
value: string | null | undefined;
|
|
3
|
+
onChange: (value: string | null) => void;
|
|
4
|
+
placeholder?: string;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function ProductCombobox({ value, onChange, placeholder, disabled }: Props): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=product-combobox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"product-combobox.d.ts","sourceRoot":"","sources":["../../../src/extras/components/product-combobox.tsx"],"names":[],"mappings":"AAgBA,KAAK,KAAK,GAAG;IACX,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IACxC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAID,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,KAAK,2CAyEhF"}
|