Bookings
Share this article
Overview
Bookings is the operational home for reservations your outfit runs through Mallard Bay. From the dashboard you can browse reservations by lifecycle status, search and organize the list, open a reservation to review trip logistics and money owed, enter internal bookings yourself, invite guests to pay through payment requests, and record another booking payment on the ledger when appropriate.
In the dashboard app routes, the main table lives at /my-bookings. Each reservation opens as a side drawer when you tap a row, or as a full-page reservation when you use View (or browse directly to /booking/{id}). Creating a reservation uses /booking/new. Two payment-related child routes attach to a booking:
/booking/{bookingId}/additional-payment— wizard titled Additional payment in the page chrome; initiated from Request payment in the reservation menu when available./booking/{bookingId}/additional-booking-payment— New booking payment flow, reachable from Create booking payment in the Payments area of the reservation.
Visiting /payment-request/{id} inside the dashboard loads that payment-request record and then opens the same full-page reservation for the linked booking—a shortcut back from guest payment workflows to the canonical booking screen.
Guests complete payment-request checkouts on the public Mallard Bay site; the dashboard builds guest-facing URLs from your environment configuration (exact domain is deployment-specific).
Prerequisites
- You are signed into the Mallard Bay admin dashboard with an outfitter workspace selected (and, for team setups, sufficient permissions to see booking actions—several menus are gated for users who cannot act on bookings or payments).
- Create booking (internal / off-platform booking entry) depends on subscription access to
OffPlatformBookings. Without it, Create booking appears locked in the bookings header. - Request payment / the Additional payment wizard is behind
AdditionalPaymentRequests. If that capability is not enabled, the Request payment action is locked and the wizard is paywalled. - For a given reservation, Request payment only appears when the booking data allows additional payment requests (
can_request_additional_paymentsfrom the API). When that is false, you will not see that path on that booking even if your plan supports payment requests globally.
No other procedural prerequisites are enforced in this repository beyond those rules and ordinary listing/availability assumptions when you compose a booking.
Use Bookings in the dashboard
1) Open Bookings (/my-bookings)
Use the sidebar Bookings entry. The screen shows a tabs row across booking states—Approved, Requested, Denied, Canceled, Completed—followed by Groups, then auction lists if your outfit uses auctions. Selecting a tab updates the status query parameter (for example ?status=APPROVED) while keeping paging, sort, search, and filter settings.
2) Search, sort, and filter
- Search: toolbar search updates
searchin the URL and resets to page 1. - Filters (opened from the table toolbar): choosing sort (“Date booked (newest/old first)”, “Start date ascending/descending”) and page size writes
sort,pageSize, and resetspageto 1. - Pagination is URL-driven alongside those parameters.
Together, navigation stays shareable—you can bookmark a filtered slice of bookings.
3) Working the list versus opening full detail
- Tap / select a booking row: opens
BookingDetailsDrawerwith the reservation content in single-column layout. BookingActions remain in the drawer header (showActionson the embedded content stays off; actions live in the header cluster). - View from the reservation actions overflow (or navigating to
/booking/{id}directly): rendersBookingDetailsView, which is intentionally the full-page reading experience (“should use full page” in layout).
Think of row selection as fast triage from the queue; View matches what you typically link or print for deeper work.
4) Understand what appears on reservation detail
The shared layout stitches together sections such as trip dates (Add to your calendar is offered there), packaged items, payouts/summary surfaces (within earnings visibility), payments, conditional Forms blocks when submissions exist, Payment requests, Unpaid balances, operational documents/guides/resources/lodging as applicable.
Team members without payment visibility will not see monetary sections flagged as hidden for their role—the code splits “payments & notes” from other content separately from earnings permissions.
5) Header actions on Bookings (/my-bookings)
- Create booking: calls
navigateToNewBookingwith asourcequery parameter tagging that you launched from Bookings (helps analytics and return context). Locked whenOffPlatformBookingsis disabled. - Create group: launches the CreateEventGroupModal from the bookings header for grouping reservations.
Groups are managed via the dedicated Groups tab panel.
6) Enter an internal booking (/booking/new)
The CreateBookingPage mounts inside a Paywall for OffPlatformBookings and resolves optional CRM context:
- If both
client_idandlead_idappear in the URL, the client wins—the lead query is skipped. lead_idalone pre-populates guest context after the lead loads.
Step-by-step UX inside each step (pricing, party, deposits, confirmations) lives in nested create-booking components and is subject to backend validation not duplicated here—follow the wizard’s validations on screen.
After a successful createBookingAsOutfitter mutation:
- You always navigate to
/booking/{bookingId}. - If you chose to request guest payment, navigation appends
?action=share_pay_link( enumerated asBookingAction.SharePayLink). On load, the booking screen finds the first unpaid payment that already has an onlinepayment_urland opens the QR/link sharing modal for that installment. If no such unpaid online payment exists, nothing auto-opens—you would continue manually from Payments. - Choices such as emailing a confirmation or payment-link email are threaded through mutation inputs configured in provider state; observable email wording and downstream notification behavior depend on Mallard Bay’s messaging stack outside this UI repository.
7) Collect new money from an existing reservation
| Goal | Where to start (dashboard) | What it does conceptually |
|---|---|---|
| Send a structured payment request (guest-facing link & tracking) | Reservation overflow → Request payment (locked if feature or booking disallow) | Loads …/additional-payment. Submission creates payment_requests surfaced under Payment requests on that booking. |
| Register another installment / payment tied to operational booking-payment records (Create booking payment button)** | Payments section → button labeled Create booking payment | Loads …/additional-booking-payment titled New booking payment. Supports payer selection plus online/offline branching through dedicated provider logic (fine-grained branching is enforced client-side hooking + GraphQL mutations not spelled out UI-step-by-step in code comments). |
Copy pitfall clarified in-product: Menu text says Request payment, whereas the routed page headline reads Additional payment—same flow.
Opening Payment requests on the reservation after creation is how you correlate outstanding guest links with bookkeeping.
Guest-facing /payment-request/{id} pages are concatenated against GATSBY_MB_ROOT_URL helpers for copying or sharing—not the SPA path you bookmark internally.
8) Deep-link from a payment request back to the booking
Hitting /payment-request/{id} inside the SPA runs usePaymentRequestQuery. When resolved, PaymentRequestRedirect reads paymentRequest.booking.id and renders BookingDetailsView for that booking—so you land on the authoritative reservation tied to that request.
If the lookup is still loading, the page spins; specifics of error surfacing vs empty responses are handled by LoadingOrErrorContainer wrappers but do not redefine business meaning.
Use this when alerts, emails, or internal links expose the payment-request id instead of an internal booking id.
Common pitfalls
- Drawer vs full page: Row click keeps you on
/my-bookingswith a drawer overlay; View or direct/booking/{id}moves you to a dedicated route. Confusion often comes from comparing screenshots or support links that differ only by which surface you used. - Request payment vs New booking payment: The first flow issues payment requests and guest links; the second records another booking payment through the Create booking payment button. Mixing them up produces mismatched expectations about whether a guest link was created.
- Feature locks: Create booking and Request payment can show as locked based on plan flags; even with the feature, Request payment may be absent when the booking’s
can_request_additional_paymentsis false. - Auto “share pay link” after create: Only triggers when an unpaid payment with a
payment_urlexists after creation. If your payment configuration does not produce that structure immediately, you will not see the automatic share modal. - Team permissions: Action menus and payment sections may be hidden or disabled for specific roles; absence of a control is not always a product bug.
- Ambiguous guest domains: The repository references a root web URL via environment variables; if documentation must state the exact checkout hostname, that value is not hard-coded here.
Related workflows (from how the app is wired)
- Listings & availability: Bookings are created against listing quotes and calendar availability; internal creation still depends on those inputs in the Create booking wizard.
- Clients & leads:
/booking/new?client_id=…and…&lead_id=…hydrate guest context; quotes and Send quote flows convert interest elsewhere but can feed the same guest records. - Calendar: Calendar screens can launch Create booking with their own
sourcetag; returning context differs but the destination/booking/newflow is shared. - Forms, waivers, onboarding: When a booking exposes
forms_with_submissions, the Forms section renders through shared library components; documents and operational readiness appear alongside payments. - Automations & templates: Guest-facing payment-request emails have dedicated template types in the editor (created, reminder, receipt, urgent reminder), indicating Mallard Bay can automate follow-up around payment requests—exact automation configuration is outside this routes summary.
- Reporting: Other surfaces (for example payment reports) can deep-link into booking drawers with highlight targets; the mental model—open booking, focus specific payment row—matches how Bookings ties into finance triage.
- Quick Pay: Quick Pay is a distinct standalone collection path (called out elsewhere in reporting code). It is not the same object as booking payment requests, though both may appear in money/reporting contexts.
If you need step-by-step field guidance inside the Additional payment multi-step form or the New booking payment modal matrix, that level of copy-by-field detail is not centralized in a single readable document in this repository—rely on the live wizard or ask support for a screen recording tailored to your payment configuration.