Order tracking screen
ProReact Native · ExpoLive order status: the arrival estimate with minutes that roll as they count down, a timeline whose line fills into each step as the order moves on (finished steps draw a check, the current one breathes), the courier with call and message buttons, and the items. Delivery lands a success check and asks for a rating.
Installation
$ npx shadcn@latest add @goodui-native-pro/order-tracking-screenThen run npx expo install --fix so react-native-reanimated, react-native-svg match your Expo SDK. Files land in components/goodui-native/order-tracking-screen.
Pro screens install from the license-gated @goodui-native-pro registry. Setup: Pro access.
- Wrap the app in GestureHandlerRootView and ThemeProvider.
Usage
// app/orders/[id].tsx
import { Linking } from "react-native";
import { Stack, router, useLocalSearchParams } from "expo-router";
import { OrderTrackingScreen } from "@/components/goodui-native/order-tracking-screen/order-tracking-screen";
import { api, useOrder } from "@/lib/orders";
export default function OrderRoute() {
const { id } = useLocalSearchParams<{ id: string }>();
const order = useOrder(id); // live: re-renders as your server pushes status updates
return (
<>
<Stack.Screen options={{ headerShown: false }} />
<OrderTrackingScreen
orderNumber={order.number}
steps={order.steps} // [{ key, title, description, time }]
currentStep={order.stepIndex} // steps.length when delivered
eta={new Date(order.eta)}
courier={order.courier} // { name, avatar, vehicle, rating }
items={order.items}
total={order.total}
currency="EUR"
onCall={() => Linking.openURL(`tel:${order.courier.phone}`)}
onMessage={() => router.push(`/orders/${id}/chat`)}
unreadMessages={order.unread}
onRateCourier={(stars) => api.rateCourier(id, stars)}
onHelp={() => router.push(`/help?order=${id}`)}
onBack={() => router.back()}
/>
</>
);
}When to use
- After checkout in a shop, grocery or food delivery app: where the order is and when it arrives.
- Any process with a few ordered steps people wait on: a repair, a pickup, a ride on its way.
- A live map with the courier's position: put your map component above this screen's content; this screen has no map.
- Past orders: list them with list-row and open a static receipt.
Examples
On its own, on its way
<OrderTrackingScreen />Delivered, asking for a rating
<OrderTrackingScreen currentStep={4} onRateCourier={(stars) => api.rate(stars)} />API reference
| Prop | Type | Default |
|---|---|---|
| orderNumber Order reference shown in the header. | string | "PN-48213" |
| steps The steps, first to last. The last one is delivery. | OrderStep[] | defaultSteps |
| currentStep Index of the step in progress (controlled). `steps.length` or more means delivered. | number | 2 |
| eta Expected arrival. The minutes left count down and roll. | Date | — |
| courier | OrderCourier | defaultCourier |
| items | OrderTrackingItem[] | defaultItems |
| total Order total in `currency`. | number | 408.8 |
| currency ISO 4217 code. Default "EUR". | string | "EUR" |
| onCall Call the courier. Hidden when omitted. | () => unknown | — |
| onMessage Message the courier. Hidden when omitted. | () => unknown | — |
| unreadMessages Unread messages from the courier, shown on the message button. | number | — |
| onHelp "Get help with this order". Hidden when omitted. | () => unknown | — |
| onRateCourier Rate the courier once delivered. Called with 1 to 5 when a tap or drag ends. | (rating: number) => unknown | — |
| onBack Back button. Hidden when omitted. | () => void | — |
| locale BCP 47 locale for times and amounts. Defaults to the device locale. | string | — |
| labels Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. | Partial<OrderTrackingScreenLabels> | — |
| style Style for the outer container. | StyleProp<ViewStyle> | — |
| testID Identifier for end-to-end tests. | string | — |
Motion and haptics
- When currentStep moves on, the line under the finished step fills down to the next dot on the smooth spring, the finished dot fills and draws its check, and the new current dot springs in (bouncy) and starts breathing.
- The minutes left roll down as the estimate counts down (checked every 15 s).
- Delivered: the success check springs in, draws, and its ring pulses; the rating stars pop as you choose.
- Reduced motion: lines and dots change at once, no breathing, the check appears complete without drawing, digits change in place.
- Haptic: tap on call and message (IconButton)
- Haptic: success when the delivery check lands (SuccessCheck)
- Haptic: select for each star while rating (Rating)
- Haptic: tap on Get help (Button)
- Each step owns two shared values (line fill, dot) and the current one a repeating halo, all on the UI thread.
- One interval re-renders the screen every 15 s to update the minutes; it stops when the screen unmounts.
Accessibility
- The header reads 'Order PN-48213' with the item count and total under it.
- The timeline is a list named 'Order progress'. On native each step is one element read as 'Packed, done, 14:02, At the Chiado store, step 2 of 4'; on the web the visible text is read with the state as visually hidden text.
- A step change is announced with the new step's title and description; delivery is announced.
- The minutes left are read as plain text ('12 minutes'); 'Expected by 14:35' is visible text.
- Call and message are labelled icon buttons ('Call Leo Martins', 'Message Leo Martins, 1 unread'). The delivery rating is adjustable with its labels (Poor to Great).
Notes for AI
- Drive currentStep from your server: the index of the step in progress; steps.length (or more) means delivered. Steps before it show their time.
- Pass eta as a Date; the screen counts the minutes itself and never shows less than 1. Without eta it uses 14 minutes from when it opened, which is only for previews.
- Buttons appear only for the callbacks you pass: onCall, onMessage, onHelp, onBack; onRateCourier shows the rating once delivered.
- Render it full-bleed with the navigator header hidden (headerShown: false); it handles the safe areas itself.
Related
The last step before paying: delivery address and payment method pickers, delivery options, the order summary with totals that roll when the delivery changes, and slide to pay in thumb reach. Paying covers the screen with a success check and confetti, then hands over through onDone.
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 photo that fades in over initials on a color picked from the name, with a presence dot and a story ring whose accent arc sweeps in when there is something new and away once seen; AvatarGroup stacks people with a +N counter and fans out on tap.
Stars (or any symbol) you tap or drag across: the fill sweeps from the old rating to the new one and every symbol it crosses pops on its own beat; half steps optional, and a read-only variant shows exact fractions with a value and a count.
A number whose digits roll in the direction of change, with digits that open and close in place and currency signs that glide instead of jumping.
Settings and navigation cells with a token-colored icon tile, title, subtitle and a trailing value, switch, badge, check or chevron, grouped in inset sections with headers and footers. On touch down the highlight floods in, the tile sinks and the chevron leans forward; on release the highlight lingers and fades.