v0.1 public beta early access on GitHub
Home / Screens / food-courier-tracking
Screen template

Courier Tracking Screen

Live delivery map (drawn SVG streets, dotted route, courier position) with ETA pill, stage dots, courier card, chronological timeline, order summary

pro Expo Go ✓ iosandroid gestures: tap · scroll haptics: light
$ npx lumioui add food-courier-tracking
import { CourierTrackingScreen } from "@/screens/food/courier-tracking";
Native packages installed6
@lumioui/ui@latestreact-native-safe-area-context@*react-native-svg@*@lumioui/core@latestreact-native-reanimated@*nativewind@*
food/courier-tracking.tsxsource · yours to edit
import * as React from "react";
import { ScrollView, View } from "react-native";
import { SafeAreaView, useSafeAreaInsets } from "react-native-safe-area-context";
import Svg, { Circle, Path, Rect } from "react-native-svg";
import { Avatar, Badge, Button, Card, Glass, Icon, Separator, Steps, Text, Timeline, type TimelineItem } from "@lumioui/ui";
import { BLOCK_STAGGER, LumioMark, Mount, Press, StickyBottomBar, World } from "../shared";

export interface FoodCourier {
  name: string;
  detail?: string;
  avatarUrl?: string;
}

export interface CourierTrackingScreenProps {
  orderId?: string;
  /** Pill overlaid on the map — "ETA 6:42 PM". */
  etaPill?: string;
  /** Headline in the status card — "Arriving in ~12 min". */
  etaHeadline?: string;
  /** Horizontal stage labels — Confirmed → Preparing → On the way → Delivered. */
  stages?: string[];
  /** Index into `stages` of the current stage. */
  stage?: number;
  /** Chronological order events — state derived from `stage`. */
  events?: { label: string; time?: string; icon?: TimelineItem["icon"] }[];
  courier?: FoodCourier;
  restaurant?: { name: string; itemCount: number };
  total?: number;
  currency?: string;
  address?: string;
  onBack?: () => void;
  onCallCourier?: () => void;
  onMessageCourier?: () => void;
  onHelp?: () => void;
}

const DEFAULT_STAGES = ["Confirmed", "Preparing", "On the way", "Delivered"];

const DEFAULT_EVENTS: { label: string; time?: string; icon?: TimelineItem["icon"] }[] = [
  { label: "Order confirmed", time: "Today, 6:12 PM", icon: "check" },
  { label: "Preparing your food", time: "Today, 6:18 PM", icon: "utensils" },
  { label: "Courier on the way", icon: "truck" },
  { label: "Delivered", icon: "map-pin" },
];

const fmt = (n: number, currency = "$") =>
  `${currency}${n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;

/** Stylized delivery map — the night-map idiom courier apps use: deep
 *  charcoal canvas, raised blocks, and the accent route cutting through.
 *  Dark regardless of scheme — it's media, not a theme surface. */
function RouteMap() {
  const ground = "#1C1917";
  const block = "#292524";
  const street = "#3F3A38";
  return (
    <Svg width="100%" height="100%" viewBox="0 0 320 176" accessible={false}>
      <Rect x={0} y={0} width={320} height={176} fill={ground} />
      {/* City blocks */}
      <Rect x={16} y={14} width={36} height={26} rx={4} fill={block} />
      <Rect x={80} y={52} width={72} height={28} rx={4} fill={block} />
      <Rect x={184} y={110} width={64} height={30} rx={4} fill={block} />
      <Rect x={280} y={96} width={30} height={40} rx={4} fill={block} />
      <Rect x={196} y={12} width={40} height={24} rx={4} fill={block} />
      {/* Streets */}
      <Path d="M0 46 H320" stroke={street} strokeWidth={11} />
      <Path d="M0 98 H320" stroke={street} strokeWidth={11} />
      <Path d="M0 150 H320" stroke={street} strokeWidth={11} />
      <Path d="M64 0 V176" stroke={street} strokeWidth={11} />
      <Path d="M170 0 V176" stroke={street} strokeWidth={11} />
      <Path d="M266 0 V176" stroke={street} strokeWidth={11} />
      {/* Route — dotted polyline, courier app idiom */}
      <Path
        d="M38 140 C 96 128, 104 60, 168 66 S 262 46, 290 36"
        stroke="#BEF04C"
        strokeWidth={3.5}
        strokeDasharray="0.1 8"
        strokeLinecap="round"
        fill="none"
      />
      {/* Origin — restaurant */}
      <Circle cx={38} cy={140} r={10} fill="#FFFFFF" stroke={ground} strokeWidth={2} />
      <Circle cx={38} cy={140} r={4} fill={ground} />
      {/* Courier — live position on the route, ringed accent disc */}
      <Circle cx={196} cy={63} r={11} fill="#FFFFFF" stroke="#BEF04C" strokeWidth={3} />
      <Circle cx={196} cy={63} r={4} fill="#BEF04C" />
      {/* Destination pin */}
      <Path
        d="M290 20c-6.6 0-12 5.4-12 12 0 9.2 12 22 12 22s12-12.8 12-22c0-6.6-5.4-12-12-12z"
        fill="#BEF04C"
      />
      <Circle cx={290} cy={32} r={4.5} fill="#FFFFFF" />
    </Svg>
  );
}
RouteMap.displayName = "RouteMap";

/** CourierTracking — drawn map with the live route, stage steps, courier
 *  card with call/message, chronological event timeline, order summary. */
export function CourierTrackingScreen({
  orderId = "NR-4821",
  etaPill = "ETA 6:42 PM",
  etaHeadline = "Arriving today, 6:30–6:42 PM",
  stages = DEFAULT_STAGES,
  stage = 2,
  events = DEFAULT_EVENTS,
  courier = {
    name: "Diego Marin",
    detail: "On the way — give him a ring",
    avatarUrl: "https://i.pravatar.cc/150?img=53",
  },
  restaurant = { name: "Nonna Rosa", itemCount: 4 },
  total = 46.0,
  currency = "$",
  address = "128 Linden St, Apt 4B",
  onBack,
  onCallCourier,
  onMessageCourier,
  onHelp,
}: CourierTrackingScreenProps) {
  const insets = useSafeAreaInsets();
  const timelineItems: TimelineItem[] = events.map((e, i) => ({
    title: e.label,
    subtitle: e.time,
    icon: e.icon,
    state: i < stage ? "done" : i === stage ? "current" : "upcoming",
  }));

  return (
    <World primary="#65A30D">
    <SafeAreaView className="flex-1 bg-[#F4F5F9] dark:bg-[#111114]" edges={["top"]}>
      <View pointerEvents="box-none" className="absolute inset-x-4 z-10" style={{ top: insets.top + 8 }}>
        <View className="flex-row items-center justify-between">
          <Glass interactive effect="regular" className="h-11 w-11 items-center justify-center rounded-full">
            <Press
              haptic="light"
              onPress={() => onBack?.()}
              accessibilityRole="button"
              accessibilityLabel="Go back"
              className="h-9 w-9 items-center justify-center"
            >
              <Icon name="chevron-left" size="md" color="foreground" />
            </Press>
          </Glass>
          <View className="h-11 w-11" />
        </View>
        <View pointerEvents="none" className="absolute inset-0 items-center justify-center">
          <View className="h-11 flex-row items-center justify-center gap-2 rounded-full pl-3.5 pr-5">
            <Glass effect="regular" className="absolute inset-0 rounded-full" />
            <LumioMark size={18} />
            <Text accessibilityRole="header" className="text-sm font-bold tracking-tight">
              Track order · {orderId}
            </Text>
          </View>
        </View>
      </View>

      <ScrollView
        className="flex-1"
        contentContainerClassName="gap-4 px-6 pb-32"
        contentContainerStyle={{ paddingTop: insets.top + 60 }}
        showsVerticalScrollIndicator={false}
      >
        {/* Map — the one thing this screen exists for. */}
        <Mount>
          <Card variant="elevated" className="overflow-hidden rounded-3xl bg-white p-0 dark:bg-[#1A1A20]">
            <View
              className="h-44"
              accessibilityLabel={`Live delivery map, ${etaHeadline}`}
              accessibilityRole="image"
            >
              <RouteMap />
            </View>
            <View className="absolute left-3 top-3 flex-row items-center gap-1.5 rounded-full px-3.5 py-2">
              <Glass effect="regular" className="absolute inset-0 rounded-full" />
              <Icon name="clock" size="sm" color="foreground" />
              <Text variant="small" className="font-semibold">
                {etaPill}
              </Text>
            </View>
            <Badge variant="success" pulse className="absolute right-3 top-3">
              Live
            </Badge>
          </Card>
        </Mount>

        {/* ETA + stage bar */}
        <Mount delay={BLOCK_STAGGER}>
          <Card variant="elevated" className="rounded-3xl bg-white dark:bg-[#1A1A20]">
            <Card.Content className="gap-4 p-4">
              <Text variant="small" className="font-semibold">
                {etaHeadline}
              </Text>
              <Steps
                steps={stages}
                current={stage}
                variant="dots"
                labels
                interactive={false}
                haptic={false}
                accessibilityLabel={`Order status: ${stages[stage]}`}
              />
            </Card.Content>
          </Card>
        </Mount>

        {/* Courier — call/message while the order is moving. */}
        {courier ? (
          <Mount delay={BLOCK_STAGGER * 2}>
            <Card variant="elevated" className="rounded-3xl bg-white dark:bg-[#1A1A20]">
              <Card.Content className="flex-row items-center gap-3 p-4">
                <Avatar
                  size="lg"
                  source={courier.avatarUrl ? { uri: courier.avatarUrl } : undefined}
                  fallback={courier.name}
                  status="online"
                  alt={`${courier.name}'s avatar`}
                />
                <View className="flex-1">
                  <Text variant="small" className="font-semibold">
                    {courier.name}
                  </Text>
                  {/* Handoff — what the courier is doing right now. */}
                  <Text variant="muted" className="text-xs">
                    Picked up your order · 4 min ago
                  </Text>
                  {courier.detail ? (
                    <Text variant="muted" className="text-xs">
                      {courier.detail}
                    </Text>
                  ) : null}
                </View>
                {onMessageCourier ? (
                  <Button
                    variant="secondary"
                    size="icon"
                    haptic="light"
                    onPress={onMessageCourier}
                    accessibilityLabel={`Message ${courier.name}`}
                  >
                    <Icon name="message-circle" size="sm" color="secondaryForeground" />
                  </Button>
                ) : null}
                {onCallCourier ? (
                  <Button
                    variant="secondary"
                    size="icon"
                    haptic="light"
                    onPress={onCallCourier}
                    accessibilityLabel={`Call ${courier.name}`}
                  >
                    <Icon name="phone" size="sm" color="secondaryForeground" />
                  </Button>
                ) : null}
              </Card.Content>
            </Card>
          </Mount>
        ) : null}

        {/* Event timeline — chronological. */}
        <Mount delay={BLOCK_STAGGER * 3}>
          <Card variant="elevated" className="rounded-3xl bg-white dark:bg-[#1A1A20]">
            <Card.Content className="p-4">
              <Timeline items={timelineItems} />
            </Card.Content>
          </Card>
        </Mount>

        {/* Order summary — where it's from, what's inside, where it lands. */}
        <Mount delay={BLOCK_STAGGER * 4}>
          <Card variant="elevated" className="rounded-3xl bg-white dark:bg-[#1A1A20]">
            <Card.Content className="gap-3 p-4">
              <View className="flex-row items-center gap-3">
                <View className="h-8 w-8 items-center justify-center rounded-lg bg-muted">
                  <Icon name="utensils" size="sm" color="mutedForeground" />
                </View>
                <Text variant="small" className="flex-1 font-semibold">
                  {restaurant.name}
                </Text>
                <Text variant="muted" className="text-xs">
                  {restaurant.itemCount} items ·{" "}
                  <Text variant="small" className="font-semibold tabular-nums">
                    {fmt(total, currency)}
                  </Text>
                </Text>
              </View>
              <Separator />
              <View className="flex-row items-center gap-3">
                <View className="h-8 w-8 items-center justify-center rounded-lg bg-[#EDF8C4]">
                  <Icon name="map-pin" size="sm" color="#65A30D" />
                </View>
                <Text variant="small" className="flex-1">
                  {address}
                </Text>
              </View>
            </Card.Content>
          </Card>
        </Mount>
      </ScrollView>

      {onHelp ? (
        <StickyBottomBar>
          <Button
            variant="secondary"
            size="lg"
            haptic="light"
            onPress={onHelp}
            accessibilityLabel="Get help with this order"
            icon={<Icon name="question-circle" size="sm" color="secondaryForeground" />}
          >
            Need help with this order?
          </Button>
        </StickyBottomBar>
      ) : null}
    </SafeAreaView>
    </World>
  );
}
CourierTrackingScreen.displayName = "CourierTrackingScreen";
agent prompt — paste into Claude Code, Cursor, Devin…
Recreate the "Courier Tracking Screen" screen in React Native using LumioUI.

Goal: Live delivery map (drawn SVG streets, dotted route, courier position) with ETA pill, stage dots, courier card, chronological timeline, order summary Match the reference implementation's layout, behavior, and motion exactly — this is a production screen, not a mockup.

## Setup

Fastest path — install the screen plus its component deps:

```bash
npx lumioui add food-courier-tracking
```

Or pull just the components: `npx lumioui add avatar badge button card glass icon separator steps text timeline`

Native packages:
- @lumioui/ui@latest
- react-native-safe-area-context@*
- react-native-svg@*
- @lumioui/core@latest
- react-native-reanimated@*
- nativewind@*

Stack assumptions: Expo SDK 54 / RN 0.81, Reanimated 4, NativeWind v4, TypeScript strict, Expo Go compatible.

## Components — how, where, when

### `avatar` — Circular user image with fallback initials and status dot.
- `<Avatar>` ×1

### `badge` — Compact status pill with variants, icons and pulse option.
- `<Badge>` ×1

### `button` — Tactile pill button with press spring, ink wash and async loading.
- `<Button>` ×3

### `card` — Compound surface — header, title, content and footer slots.
- `<Card>` ×5

### `glass` — iOS 26 liquid-glass surface — real glass via expo-glass-effect (Expo Go) or @callstack/liquid-glass (dev builds), SVG refraction + specular rim on web, frosted fallback elsewhere; GlassContainer melts adjacent panes into one blob
- `<Glass>` ×3

### `icon` — Lucide icon set mapped to theme colors and sizes.
- `<Icon>` ×7

### `separator` — Hairline rule with orientation and spacing control.
- `<Separator>` ×1

### `steps` — Horizontal step indicator with numbered or dot markers, check-on-complete pop, and connectors that fill as progress advances
- `<Steps>` ×1

### `text` — Themed type scale from caption to display.
- `<Text>` ×10

### `timeline` — Vertical step tracker for orders, shipping and onboarding — animated connector fill, live-node pulse, per-state icons
- `<Timeline>` ×1

## Conventions (non-negotiable)

- Styling via NativeWind `className` with semantic tokens only: `bg-background`, `text-foreground`, `bg-card`, `text-card-foreground`, `bg-secondary`, `bg-muted`, `text-muted-foreground`, `bg-accent`, `bg-destructive`, `border-border`. Hard-coded colors only inside media overlays (`text-white`, `bg-black/N`).
- Motion via the token presets from `@lumioui/core` (`spring.press`, `spring.surface`, `spring.glide`, `timing.fast`, `timing.slow`, …) — no bespoke spring configs or durations.
- Gate transform motion behind `useReducedMotion()`; keep opacity/color feedback, drop travel and overshoot.
- Haptics via `useHaptic()`: `light` on press, `selection` on toggle/select, `warning` on invalid input. Never import expo-haptics directly.
- Press feedback via `usePressAnimation()` (~0.97 scale), not `activeOpacity` tricks.
- a11y: `accessibilityRole` + `accessibilityLabel` on every control, touch targets ≥44pt.
- Entrance choreography: staggered `Mount` wrappers (delay 0/60/120…) so regions land in sequence instead of popping in at once.
- Wrap the screen in `SafeAreaView`; keep dark mode working via the semantic tokens.

## Deliverable

One file: `screens/food/courier-tracking.tsx` exporting CourierTrackingScreen. Preserve the props interface — the host app wires the callbacks (navigation, submit handlers) through them.

## Reference implementation

The LumioUI source for this screen — reproduce it faithfully:

```tsx
import * as React from "react";
import { ScrollView, View } from "react-native";
import { SafeAreaView, useSafeAreaInsets } from "react-native-safe-area-context";
import Svg, { Circle, Path, Rect } from "react-native-svg";
import { Avatar, Badge, Button, Card, Glass, Icon, Separator, Steps, Text, Timeline, type TimelineItem } from "@lumioui/ui";
import { BLOCK_STAGGER, LumioMark, Mount, Press, StickyBottomBar, World } from "../shared";

export interface FoodCourier {
  name: string;
  detail?: string;
  avatarUrl?: string;
}

export interface CourierTrackingScreenProps {
  orderId?: string;
  /** Pill overlaid on the map — "ETA 6:42 PM". */
  etaPill?: string;
  /** Headline in the status card — "Arriving in ~12 min". */
  etaHeadline?: string;
  /** Horizontal stage labels — Confirmed → Preparing → On the way → Delivered. */
  stages?: string[];
  /** Index into `stages` of the current stage. */
  stage?: number;
  /** Chronological order events — state derived from `stage`. */
  events?: { label: string; time?: string; icon?: TimelineItem["icon"] }[];
  courier?: FoodCourier;
  restaurant?: { name: string; itemCount: number };
  total?: number;
  currency?: string;
  address?: string;
  onBack?: () => void;
  onCallCourier?: () => void;
  onMessageCourier?: () => void;
  onHelp?: () => void;
}

const DEFAULT_STAGES = ["Confirmed", "Preparing", "On the way", "Delivered"];

const DEFAULT_EVENTS: { label: string; time?: string; icon?: TimelineItem["icon"] }[] = [
  { label: "Order confirmed", time: "Today, 6:12 PM", icon: "check" },
  { label: "Preparing your food", time: "Today, 6:18 PM", icon: "utensils" },
  { label: "Courier on the way", icon: "truck" },
  { label: "Delivered", icon: "map-pin" },
];

const fmt = (n: number, currency = "$") =>
  `${currency}${n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;

/** Stylized delivery map — the night-map idiom courier apps use: deep
 *  charcoal canvas, raised blocks, and the accent route cutting through.
 *  Dark regardless of scheme — it's media, not a theme surface. */
function RouteMap() {
  const ground = "#1C1917";
  const block = "#292524";
  const street = "#3F3A38";
  return (
    <Svg width="100%" height="100%" viewBox="0 0 320 176" accessible={false}>
      <Rect x={0} y={0} width={320} height={176} fill={ground} />
      {/* City blocks */}
      <Rect x={16} y={14} width={36} height={26} rx={4} fill={block} />
      <Rect x={80} y={52} width={72} height={28} rx={4} fill={block} />
      <Rect x={184} y={110} width={64} height={30} rx={4} fill={block} />
      <Rect x={280} y={96} width={30} height={40} rx={4} fill={block} />
      <Rect x={196} y={12} width={40} height={24} rx={4} fill={block} />
      {/* Streets */}
      <Path d="M0 46 H320" stroke={street} strokeWidth={11} />
      <Path d="M0 98 H320" stroke={street} strokeWidth={11} />
      <Path d="M0 150 H320" stroke={street} strokeWidth={11} />
      <Path d="M64 0 V176" stroke={street} strokeWidth={11} />
      <Path d="M170 0 V176" stroke={street} strokeWidth={11} />
      <Path d="M266 0 V176" stroke={street} strokeWidth={11} />
      {/* Route — dotted polyline, courier app idiom */}
      <Path
        d="M38 140 C 96 128, 104 60, 168 66 S 262 46, 290 36"
        stroke="#BEF04C"
        strokeWidth={3.5}
        strokeDasharray="0.1 8"
        strokeLinecap="round"
        fill="none"
      />
      {/* Origin — restaurant */}
      <Circle cx={38} cy={140} r={10} fill="#FFFFFF" stroke={ground} strokeWidth={2} />
      <Circle cx={38} cy={140} r={4} fill={ground} />
      {/* Courier — live position on the route, ringed accent disc */}
      <Circle cx={196} cy={63} r={11} fill="#FFFFFF" stroke="#BEF04C" strokeWidth={3} />
      <Circle cx={196} cy={63} r={4} fill="#BEF04C" />
      {/* Destination pin */}
      <Path
        d="M290 20c-6.6 0-12 5.4-12 12 0 9.2 12 22 12 22s12-12.8 12-22c0-6.6-5.4-12-12-12z"
        fill="#BEF04C"
      />
      <Circle cx={290} cy={32} r={4.5} fill="#FFFFFF" />
    </Svg>
  );
}
RouteMap.displayName = "RouteMap";

/** CourierTracking — drawn map with the live route, stage steps, courier
 *  card with call/message, chronological event timeline, order summary. */
export function CourierTrackingScreen({
  orderId = "NR-4821",
  etaPill = "ETA 6:42 PM",
  etaHeadline = "Arriving today, 6:30–6:42 PM",
  stages = DEFAULT_STAGES,
  stage = 2,
  events = DEFAULT_EVENTS,
  courier = {
    name: "Diego Marin",
    detail: "On the way — give him a ring",
    avatarUrl: "https://i.pravatar.cc/150?img=53",
  },
  restaurant = { name: "Nonna Rosa", itemCount: 4 },
  total = 46.0,
  currency = "$",
  address = "128 Linden St, Apt 4B",
  onBack,
  onCallCourier,
  onMessageCourier,
  onHelp,
}: CourierTrackingScreenProps) {
  const insets = useSafeAreaInsets();
  const timelineItems: TimelineItem[] = events.map((e, i) => ({
    title: e.label,
    subtitle: e.time,
    icon: e.icon,
    state: i < stage ? "done" : i === stage ? "current" : "upcoming",
  }));

  return (
    <World primary="#65A30D">
    <SafeAreaView className="flex-1 bg-[#F4F5F9] dark:bg-[#111114]" edges={["top"]}>
      <View pointerEvents="box-none" className="absolute inset-x-4 z-10" style={{ top: insets.top + 8 }}>
        <View className="flex-row items-center justify-between">
          <Glass interactive effect="regular" className="h-11 w-11 items-center justify-center rounded-full">
            <Press
              haptic="light"
              onPress={() => onBack?.()}
              accessibilityRole="button"
              accessibilityLabel="Go back"
              className="h-9 w-9 items-center justify-center"
            >
              <Icon name="chevron-left" size="md" color="foreground" />
            </Press>
          </Glass>
          <View className="h-11 w-11" />
        </View>
        <View pointerEvents="none" className="absolute inset-0 items-center justify-center">
          <View className="h-11 flex-row items-center justify-center gap-2 rounded-full pl-3.5 pr-5">
            <Glass effect="regular" className="absolute inset-0 rounded-full" />
            <LumioMark size={18} />
            <Text accessibilityRole="header" className="text-sm font-bold tracking-tight">
              Track order · {orderId}
            </Text>
          </View>
        </View>
      </View>

      <ScrollView
        className="flex-1"
        contentContainerClassName="gap-4 px-6 pb-32"
        contentContainerStyle={{ paddingTop: insets.top + 60 }}
        showsVerticalScrollIndicator={false}
      >
        {/* Map — the one thing this screen exists for. */}
        <Mount>
          <Card variant="elevated" className="overflow-hidden rounded-3xl bg-white p-0 dark:bg-[#1A1A20]">
            <View
              className="h-44"
              accessibilityLabel={`Live delivery map, ${etaHeadline}`}
              accessibilityRole="image"
            >
              <RouteMap />
            </View>
            <View className="absolute left-3 top-3 flex-row items-center gap-1.5 rounded-full px-3.5 py-2">
              <Glass effect="regular" className="absolute inset-0 rounded-full" />
              <Icon name="clock" size="sm" color="foreground" />
              <Text variant="small" className="font-semibold">
                {etaPill}
              </Text>
            </View>
            <Badge variant="success" pulse className="absolute right-3 top-3">
              Live
            </Badge>
          </Card>
        </Mount>

        {/* ETA + stage bar */}
        <Mount delay={BLOCK_STAGGER}>
          <Card variant="elevated" className="rounded-3xl bg-white dark:bg-[#1A1A20]">
            <Card.Content className="gap-4 p-4">
              <Text variant="small" className="font-semibold">
                {etaHeadline}
              </Text>
              <Steps
                steps={stages}
                current={stage}
                variant="dots"
                labels
                interactive={false}
                haptic={false}
                accessibilityLabel={`Order status: ${stages[stage]}`}
              />
            </Card.Content>
          </Card>
        </Mount>

        {/* Courier — call/message while the order is moving. */}
        {courier ? (
          <Mount delay={BLOCK_STAGGER * 2}>
            <Card variant="elevated" className="rounded-3xl bg-white dark:bg-[#1A1A20]">
              <Card.Content className="flex-row items-center gap-3 p-4">
                <Avatar
                  size="lg"
                  source={courier.avatarUrl ? { uri: courier.avatarUrl } : undefined}
                  fallback={courier.name}
                  status="online"
                  alt={`${courier.name}'s avatar`}
                />
                <View className="flex-1">
                  <Text variant="small" className="font-semibold">
                    {courier.name}
                  </Text>
                  {/* Handoff — what the courier is doing right now. */}
                  <Text variant="muted" className="text-xs">
                    Picked up your order · 4 min ago
                  </Text>
                  {courier.detail ? (
                    <Text variant="muted" className="text-xs">
                      {courier.detail}
                    </Text>
                  ) : null}
                </View>
                {onMessageCourier ? (
                  <Button
                    variant="secondary"
                    size="icon"
                    haptic="light"
                    onPress={onMessageCourier}
                    accessibilityLabel={`Message ${courier.name}`}
                  >
                    <Icon name="message-circle" size="sm" color="secondaryForeground" />
                  </Button>
                ) : null}
                {onCallCourier ? (
                  <Button
                    variant="secondary"
                    size="icon"
                    haptic="light"
                    onPress={onCallCourier}
                    accessibilityLabel={`Call ${courier.name}`}
                  >
                    <Icon name="phone" size="sm" color="secondaryForeground" />
                  </Button>
                ) : null}
              </Card.Content>
            </Card>
          </Mount>
        ) : null}

        {/* Event timeline — chronological. */}
        <Mount delay={BLOCK_STAGGER * 3}>
          <Card variant="elevated" className="rounded-3xl bg-white dark:bg-[#1A1A20]">
            <Card.Content className="p-4">
              <Timeline items={timelineItems} />
            </Card.Content>
          </Card>
        </Mount>

        {/* Order summary — where it's from, what's inside, where it lands. */}
        <Mount delay={BLOCK_STAGGER * 4}>
          <Card variant="elevated" className="rounded-3xl bg-white dark:bg-[#1A1A20]">
            <Card.Content className="gap-3 p-4">
              <View className="flex-row items-center gap-3">
                <View className="h-8 w-8 items-center justify-center rounded-lg bg-muted">
                  <Icon name="utensils" size="sm" color="mutedForeground" />
                </View>
                <Text variant="small" className="flex-1 font-semibold">
                  {restaurant.name}
                </Text>
                <Text variant="muted" className="text-xs">
                  {restaurant.itemCount} items ·{" "}
                  <Text variant="small" className="font-semibold tabular-nums">
                    {fmt(total, currency)}
                  </Text>
                </Text>
              </View>
              <Separator />
              <View className="flex-row items-center gap-3">
                <View className="h-8 w-8 items-center justify-center rounded-lg bg-[#EDF8C4]">
                  <Icon name="map-pin" size="sm" color="#65A30D" />
                </View>
                <Text variant="small" className="flex-1">
                  {address}
                </Text>
              </View>
            </Card.Content>
          </Card>
        </Mount>
      </ScrollView>

      {onHelp ? (
        <StickyBottomBar>
          <Button
            variant="secondary"
            size="lg"
            haptic="light"
            onPress={onHelp}
            accessibilityLabel="Get help with this order"
            icon={<Icon name="question-circle" size="sm" color="secondaryForeground" />}
          >
            Need help with this order?
          </Button>
        </StickyBottomBar>
      ) : null}
    </SafeAreaView>
    </World>
  );
}
CourierTrackingScreen.displayName = "CourierTrackingScreen";
```

Screen: https://lumioui.dev/screens/food-courier-tracking
iPhone 17 · iOS
9:41
Live preview — the real screen via Expo Web · open full ↗