Booking confirm screen
ProReact Native · ExpoThe last step of a booking flow: a summary card, client details, notes and the cancellation policy, booked with a slide (or a button). The slider spins while the request runs, then the screen gives way to a success check with confetti, Add to calendar and Done.
Installation
$ npx shadcn@latest add @goodui-native-pro/booking-confirm-screenThen run npx expo install --fix so react-native-reanimated match your Expo SDK. Files land in components/goodui-native/booking-confirm-screen.
Pro screens install from the license-gated @goodui-native-pro registry. Setup: Pro access.
Usage
import { router, Stack } from "expo-router";
import { BookingConfirmScreen } from "@/components/goodui-native/booking-confirm-screen/booking-confirm-screen";
import { api } from "@/lib/api";
import { addToCalendar } from "@/lib/calendar"; // for example with expo-calendar
import { useBookingDraft, useSession } from "@/lib/booking";
export default function ConfirmRoute() {
const draft = useBookingDraft();
const { user } = useSession();
return (
<>
<Stack.Screen options={{ headerShown: false }} />
<BookingConfirmScreen
business={draft.business}
items={draft.items}
staff={draft.staff}
start={draft.start}
client={{ name: user?.name, email: user?.email }}
onBack={() => router.back()}
onEdit={() => router.back()}
onConfirm={(details) => api.book({ ...draft.toRequest(), client: details })} // resolves with { reference }
onAddToCalendar={(appointment) => addToCalendar(appointment)}
onDone={() => router.dismissAll()}
/>
</>
);
}When to use
- Reviewing and confirming an appointment before it is booked, with the client's contact details.
- Bookings with a cancellation or no-show policy the client must accept.
- Flows that end on a clear booked moment with Add to calendar.
- Paying for physical goods: use checkout-screen.
- Editing an existing appointment: use booking-details-screen with reschedule.
- A single yes or no question: use alert-dialog.
Examples
Sample visit, no props
<BookingConfirmScreen />Button instead of a slide, no policy checkbox
<BookingConfirmScreen confirmMode="button" requirePolicy={false} onConfirm={book} onDone={close} />API reference
| Prop | Type | Default |
|---|---|---|
| business The business; its name, address, currency and cancellation policy show on the screen. | BookingBusiness | sampleBusiness |
| items What is being booked, services then add-ons. Duration and total are their sums. | BookingLineItem[] | — |
| staff Who it is with. `null` is "Any available". | BookingStaff | null | sampleStaff[0] |
| start Start of the appointment. | Date | — |
| client Prefill for the client fields, for example from the signed-in account. | Partial<BookingClient> | — |
| onConfirm Books it. Runs only once the fields are valid and the policy is accepted. Return a promise: while it is pending the slider spins; resolve (optionally with `{ reference }`) to show the success screen, reject with an `Error` whose message is person-facing ("That time was just taken") to shake the slider and show it. | (details: BookingConfirmDetails) => unknown | — |
| confirmMode `swipe` books with a slide (deliberate, no accidental taps); `button` with a primary button. Default `swipe`. | "swipe" | "button" | "swipe" |
| requirePolicy Require ticking the cancellation policy before booking. Default `true`. | boolean | true |
| onAddToCalendar "Add to calendar" on the success screen, with the booked appointment. Return a promise to show pending and done. | (appointment: Appointment) => unknown | — |
| onDone "Done" on the success screen. Navigate away here. | (appointment: Appointment) => void | — |
| onEdit Shows "Change" on the summary card, for going back to the time step. | () => void | — |
| onBack Shows a back button in the top bar. Hidden on the success screen. | () => void | — |
| paymentNote How payment works, under the total. Default "Pay at the salon after your visit. No card needed." Same as `labels.paymentNote`. | string | — |
| step Step of the booking flow in the top bar. `null` hides it. Default step 4 of 4. | BookingStep | null | { current: 4, total: 4 } |
| title Headline. Default "Review and confirm". Same as `labels.title`. | string | — |
| locale BCP 47 locale for dates, times and prices. Defaults to the device locale. | string | — |
| hour12 Force a 12 or 24 hour clock. Defaults to the locale's. | boolean | — |
| labels Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. | Partial<BookingConfirmScreenLabels> | — |
| style Style for the outer container. | StyleProp<ViewStyle> | — |
| testID Identifier for end-to-end tests. | string | — |
Motion and haptics
- The slide follows the finger 1:1 and spins while onConfirm runs; a rejection shakes it with the message and it springs back.
- On success the slider shows its check, then the screen crossfades to a success check that springs in, draws its mark and bursts confetti (the one bouncy moment of the flow).
- Reduced motion: the slider and the check follow their own reduced-motion rules (the check fades in complete, confetti shows a static sparkle), the screens crossfade.
- Haptic: select at the slider's point of no return, confirm or error when the booking settles (SwipeToConfirm)
- Haptic: celebrate as the success check lands with its confetti (SuccessCheck)
- Haptic: error when a field error appears (TextField)
- Validation is a pure function of the field values; nothing re-renders per keystroke beyond the field itself and its error line.
- On Android the keyboard height pads the scroll view; on iOS the scroll view adjusts its own inset. The bottom bar steps aside while the keyboard is up.
Accessibility
- Fields are TextFields with labels, autocomplete hints and errors that are announced; Next on the keyboard moves through name, email, phone and notes.
- Errors show only after the first attempt and then follow the typing. A failed attempt scrolls the form into view.
- The policy is a checkbox that turns red with a written reason when it is required and unticked.
- The slider is the kit's SwipeToConfirm: a button for screen readers (activating it confirms) with a hint naming the day and time; confirmMode='button' gives a plain button.
- The success screen's check announces its title; the reference and the confirmation email are text.
Notes for AI
- onConfirm(details) runs only when name and email are valid and the policy is ticked. Resolve with { reference } to show it; reject with an Error whose message is person-facing to show it on the slider.
- items are BookingLineItem[] (use lineItemsFor(cart, services, addOns) from booking-types). start is a Date.
- Add to calendar shows only when onAddToCalendar is passed; it receives the booked Appointment.
- Prefill client from the signed-in account; phone is optional.
- Hide the navigator header (headerShown: false).
Related
Step three of a booking flow: a week strip, the day's times grouped by morning, afternoon and evening for the chosen professional, a time zone note, and a summary that springs up from the bottom with the time rolling in on every pick.
Slide to confirm: the thumb follows the finger 1:1, the track fills behind it and the label fades, a tick marks the point of no return, and at the end the track gathers into a spinner and opens into the result.
A success or error moment: the circle springs in, the check draws itself while a ring pulses out and the title rises in; the error variant draws a cross and shakes once. Inline or fullscreen, optionally with confetti.
A text field whose label glides up as you focus it, with helper and error text that slide in, a shake and haptic on error, clear and reveal buttons, a character counter and a multiline mode that grows with its text.
Checkboxes whose check draws itself in (an indeterminate dash retracts into it) and radios whose dot pops into the center, inline or as list rows, with CheckboxGroup and RadioGroup helpers.
A client's bookings in Upcoming and Past tabs: date-tile cards with status, time, professional and place. Swipe a card for Reschedule or Cancel; cancelling asks in an alert that spins while the request runs, then the card slides out of Upcoming and the tab count drops.