Appointments screen
ProReact Native · ExpoA 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.
Installation
$ npx shadcn@latest add @goodui-native-pro/appointments-screenThen run npx expo install --fix so react-native-reanimated match your Expo SDK. Files land in components/goodui-native/appointments-screen.
Pro screens install from the license-gated @goodui-native-pro registry. Setup: Pro access.
Usage
import { router, Stack } from "expo-router";
import { AppointmentsScreen } from "@/components/goodui-native/appointments-screen/appointments-screen";
import { api } from "@/lib/api";
import { useAppointments } from "@/lib/booking"; // your data, Appointment[]
export default function AppointmentsRoute() {
const { data, refresh } = useAppointments();
return (
<>
<Stack.Screen options={{ headerShown: false }} />
<AppointmentsScreen
appointments={data}
onOpen={(a) => router.push({ pathname: "/appointments/[id]", params: { id: a.id } })}
onReschedule={(a) => router.push({ pathname: "/book/time", params: { reschedule: a.id } })}
onCancel={(a) => api.cancel(a.id).then(refresh)}
onBookAgain={(a) => router.push({ pathname: "/book", params: { again: a.id } })}
onBook={() => router.push("/book")}
/>
</>
);
}When to use
- The bookings tab of a client app for a salon, clinic, studio, gym or tutor.
- Lists where each item has quick actions (reschedule, cancel, book again) and a details screen.
- A staff calendar with many bookings per day: use a timeline or calendar view.
- Notifications or messages: use inbox-screen.
- One appointment's details: use booking-details-screen.
Examples
Sample appointments, no props
<AppointmentsScreen />Empty
<AppointmentsScreen appointments={[]} onBook={() => router.push("/book")} />API reference
| Prop | Type | Default |
|---|---|---|
| appointments Every appointment, any order. Confirmed and pending ones that have not started are upcoming; the rest are past. | Appointment[] | — |
| onOpen Tapping a card, for example to push the details screen. | (appointment: Appointment) => void | — |
| onReschedule The Reschedule swipe action on an upcoming card. Hidden when omitted. | (appointment: Appointment) => void | — |
| onCancel Cancels after the person confirms in the alert. Return a promise: the alert keeps a spinner until it settles, closes on success (the card leaves Upcoming and shows as cancelled under Past) and shakes on failure. | (appointment: Appointment) => unknown | — |
| onBookAgain The Book again swipe action on a past card. Hidden when omitted. | (appointment: Appointment) => void | — |
| onBook New booking: the plus button in the header and the empty state's button. Hidden when omitted. | () => void | — |
| onAppointmentsChange Called with the whole list after a cancellation changes it, to keep your store in sync. | (appointments: Appointment[]) => void | — |
| defaultTab Tab shown first. Default "upcoming". | "upcoming" | "past" | "upcoming" |
| title Headline. Default "Appointments". Same as `labels.title`. | string | — |
| locale BCP 47 locale for dates and times. Defaults to the device locale. | string | — |
| hour12 Force a 12 or 24 hour clock. Defaults to the locale's. | boolean | — |
| now The current time, for splitting upcoming from past. Default now. | Date | — |
| labels Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. | Partial<AppointmentsScreenLabels> | — |
| style Style for the outer container. | StyleProp<ViewStyle> | — |
| testID Identifier for end-to-end tests. | string | — |
Motion and haptics
- Cards follow the finger and unfold Cancel and Reschedule in proportion to the drag (SwipeActions).
- After a confirmed cancellation the card fades out and the cards below slide up into its place; the Upcoming count badge updates.
- Empty states draw their line art in.
- Reduced motion: cards below jump into place instead of sliding; the components inside follow their own reduced-motion rules.
- Haptic: tap when a swipe action runs (SwipeActions)
- Haptic: select when the tab changes (TopTabs)
- Haptic: success or error when the cancellation settles (AlertDialog)
- Upcoming and Past are derived with useMemo from one list; a page mounts only when its tab is first shown (TopTabs lazy).
- For hundreds of appointments, page the data from your API; each page is a ScrollView.
Accessibility
- Tabs are the kit's TopTabs (tablist with selected state and a count on Upcoming).
- Each card is one button: on native it reads as a sentence (services, day, time, professional, status) and offers Reschedule and Cancel as accessibility actions; the web names it from its text and opens it with Enter or Space.
- Cancelling always asks first in an AlertDialog that names the visit and the free cancellation window or the late fee.
- A line under each list says that cards can be swiped, so the actions are discoverable.
Notes for AI
- appointments is Appointment[] from booking-types. Confirmed and pending ones that have not ended are Upcoming; everything else is Past.
- onCancel runs only after the alert is confirmed. Return a promise; on success the screen marks the appointment cancelled locally and calls onAppointmentsChange with the new list.
- Swiping between tabs is off on purpose: horizontal swipes belong to the cards. Tabs change with a tap.
- Reschedule and Book again appear only when their callbacks are passed; Cancel is always offered on upcoming cards.
- Hide the navigator header (headerShown: false); the screen draws its own title.
Related
One appointment in full: status badge and reference, the day and time with how far away it is, the professional, the services and total, a map card with Directions and Call, Add to calendar, Reschedule, and a hold-to-cancel that names the free cancellation window.
Row actions that unfold with the finger; a long swipe lets the edge action take over and run, and destructive actions collapse the row before it leaves.
A swipeable pager under a tab strip whose indicator tracks the swipe continuously: the leading edge runs ahead and the trailing edge follows, so it stretches between tabs and gathers as the page lands. Labels recolor with the swipe and a scrolling strip keeps the indicator centred.
A centered alert that springs in from slightly larger; touch an action and slide across the others with a tick per action, tap outside and it nudges, and async actions keep it open with a spinner until they settle.
A designed empty, error or offline state: a tinted disc pops in, its line art draws itself stroke by stroke with the highlight landing last, then the title, description and actions rise in.
Step one of a booking flow: the menu in sticky category sections with duration and price, add-ons that spring up as chips once a matching service is picked, and a total that rolls with every change above the Continue button. Also ships the booking data model shared by every booking screen.