# Appointments screen

> 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.

- Type: Component (screens)
- Access: Pro
- Page: https://goodui.dev/native/components/appointments-screen
- Markdown: https://goodui.dev/native/components/appointments-screen.md
- Registry item: https://goodui.dev/native/r/appointments-screen.json
- Dependencies: react-native-reanimated
- Keywords: react native my bookings, appointments list screen, upcoming and past bookings, cancel appointment swipe, reschedule booking, salon client app, expo appointments

## 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.

## When not to use

- 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.

## Installation

With the shadcn CLI (needs a components.json in the Expo app), then `npx expo install --fix` so native dependencies match your Expo SDK. The foundation comes along the first time.

```bash
npx shadcn@latest add @goodui-native-pro/appointments-screen
npx expo install --fix
```

Pro: add `"@goodui-native-pro": { "url": "https://goodui.dev/native/r/pro/{name}.json", "headers": { "Authorization": "Bearer ${GOODUI_LICENSE_KEY}" } }` to the `registries` of components.json and put your license key in .env.local.

The component lands in `components/goodui-native/appointments-screen/` and imports the foundation from `components/goodui-native/foundation/` with relative paths; it also installs alert-dialog, avatar, badge, empty-state, icon-button, locale, service-picker-screen, swipe-actions, top-tabs.

Built-in strings follow `<GooduiLocaleProvider>` (one [language pack](https://goodui.dev/native/r/locale-tr.json) translates the whole kit); the `labels` prop overrides them for one instance.

## Usage

```tsx
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")}
      />
    </>
  );
}
```

## Examples

### Sample appointments, no props

```tsx
<AppointmentsScreen />
```

### Empty

```tsx
<AppointmentsScreen appointments={[]} onBook={() => router.push("/book")} />
```

## API reference

### AppointmentsScreen

`import { AppointmentsScreen } from "@/components/goodui-native/appointments-screen/appointments-screen";`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `appointments` | `Appointment[]` | – | Every appointment, any order. Confirmed and pending ones that have not started are upcoming; the rest are past. |
| `onOpen` | `(appointment: Appointment) => void` | – | Tapping a card, for example to push the details screen. |
| `onReschedule` | `(appointment: Appointment) => void` | – | The Reschedule swipe action on an upcoming card. Hidden when omitted. |
| `onCancel` | `(appointment: Appointment) => unknown` | – | 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. |
| `onBookAgain` | `(appointment: Appointment) => void` | – | The Book again swipe action on a past card. Hidden when omitted. |
| `onBook` | `() => void` | – | New booking: the plus button in the header and the empty state's button. Hidden when omitted. |
| `onAppointmentsChange` | `(appointments: Appointment[]) => void` | – | Called with the whole list after a cancellation changes it, to keep your store in sync. |
| `defaultTab` | `"upcoming" \| "past"` | `"upcoming"` | Tab shown first. Default "upcoming". |
| `title` | `string` | – | Headline. Default "Appointments". Same as `labels.title`. |
| `locale` | `string` | – | BCP 47 locale for dates and times. Defaults to the device locale. |
| `hour12` | `boolean` | – | Force a 12 or 24 hour clock. Defaults to the locale's. |
| `now` | `Date` | – | The current time, for splitting upcoming from past. Default now. |
| `labels` | `Partial<AppointmentsScreenLabels>` | – | Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. |
| `style` | `StyleProp<ViewStyle>` | – | Style for the outer container. |
| `testID` | `string` | – | Identifier for end-to-end tests. |

## 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.

## Motion

- 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.

## Haptics

- tap when a swipe action runs (SwipeActions)
- select when the tab changes (TopTabs)
- success or error when the cancellation settles (AlertDialog)

## Performance

- 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.

## 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

- [Booking details screen](https://goodui.dev/native/components/booking-details-screen.md): 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.
- [Swipe actions](https://goodui.dev/native/components/swipe-actions.md): 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.
- [Top tabs](https://goodui.dev/native/components/top-tabs.md): 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.
- [Alert dialog](https://goodui.dev/native/components/alert-dialog.md): 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.
- [Empty state](https://goodui.dev/native/components/empty-state.md): 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.
- [Service picker screen](https://goodui.dev/native/components/service-picker-screen.md): 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.

## Guidance for AI tools

Appointments screen: 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. Use only the documented props. Keep accessibility, reduced motion and both color schemes intact when adapting it.

Full library index: https://goodui.dev/native/llms.txt
