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

Order Tracking Screen

Delivery tracking — ETA hero with a stage progress bar, vertical event timeline, courier card with call/message actions, pickup-to-doorstep route, and an items strip

pro Expo Go ✓ iosandroid gestures: tap · scroll haptics: light
$ npx lumioui add ecommerce-tracking
import { OrderTrackingScreen } from "@/screens/ecommerce/tracking";
Native packages installed6
@lumioui/ui@latest@lumioui/core@latestreact-native-safe-area-context@*react-native-reanimated@*react-native-svg@*nativewind@*
ecommerce/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 { Avatar, Button, Card, Glass, Icon, Image, Separator, Steps, Text, type IconName } from "@lumioui/ui";
import { cn } from "@lumioui/core";
import { catalogImg, LumioMark, Mount, Press, StickyBottomBar, World } from "../shared";

export interface TrackingEvent {
  label: string;
  /** "Today, 2:41 PM" — blank for events that haven't happened yet. */
  time?: string;
  icon?: IconName;
}

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

export interface OrderTrackingScreenProps {
  orderId?: string;
  /** Headline ETA — "Arriving Thursday, Sep 18". */
  eta?: string;
  etaDetail?: string;
  /** Horizontal stage labels — Ordered → Shipped → Out for delivery → Delivered. */
  stages?: string[];
  /** Index into `stages` of the current stage. */
  stage?: number;
  /** Vertical event log under the stage bar. */
  events?: TrackingEvent[];
  courier?: Courier;
  /** Pickup → destination rows. */
  from?: string;
  to?: string;
  items?: { name: string; imageUrl?: string }[];
  total?: number;
  currency?: string;
  onBack?: () => void;
  onCallCourier?: () => void;
  onMessageCourier?: () => void;
  onHelp?: () => void;
}

const img = (p: Parameters<typeof catalogImg>[0]) => catalogImg(p, 160, 200);

const DEFAULT_STAGES = ["Ordered", "Shipped", "Out for delivery", "Delivered"];

const DEFAULT_EVENTS: TrackingEvent[] = [
  { label: "Out for delivery", time: "Today, 9:12 AM", icon: "truck" },
  { label: "Arrived at local facility", time: "Today, 6:40 AM", icon: "package" },
  { label: "Departed regional hub", time: "Yesterday, 8:15 PM", icon: "package" },
  { label: "Picked up by courier", time: "Sep 15, 4:02 PM", icon: "package" },
  { label: "Order confirmed", time: "Sep 15, 11:30 AM", icon: "check-circle" },
];

const DEFAULT_ITEMS = [
  { name: "Structured Wool Overcoat", imageUrl: img("overcoat") },
  { name: "Garment-Dyed Tee", imageUrl: img("tee") },
  { name: "Heritage Graphic Tee", imageUrl: img("graphicTee") },
];

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

/** Vertical timeline row — icon dot, connector line, label + time.
 *  The last row drops the connector. */
function TimelineRow({
  event,
  done,
  last,
}: {
  event: TrackingEvent;
  done: boolean;
  last: boolean;
}) {
  return (
    <View className="flex-row gap-3" accessibilityElementsHidden={!done}>
      <View className="items-center">
        <View
          className={cn(
            "h-7 w-7 items-center justify-center rounded-full",
            done ? "bg-[#EDF8C4] dark:bg-[#1E2410]" : "bg-muted"
          )}
        >
          <Icon
            name={event.icon ?? "check"}
            size="sm"
            color={done ? "#65A30D" : "mutedForeground"}
          />
        </View>
        {!last ? <View className={cn("w-px flex-1", done ? "bg-[#BEF04C]" : "bg-border")} /> : null}
      </View>
      <View className="flex-1 pb-4">
        <Text variant="small" className={cn(done ? "font-semibold" : "text-muted-foreground")}>
          {event.label}
        </Text>
        {event.time ? (
          <Text variant="muted" className="text-xs tabular-nums">
            {event.time}
          </Text>
        ) : null}
      </View>
    </View>
  );
}
TimelineRow.displayName = "TimelineRow";

/** OrderTracking — ETA hero with the horizontal stage bar, vertical event
 *  timeline, courier card, route card, and the items strip. The delivery
 *  pattern every shipped-order app lands on. */
export function OrderTrackingScreen({
  orderId = "HL-2094",
  eta = "Arriving today",
  etaDetail = "Estimated between 4–6 PM",
  stages = DEFAULT_STAGES,
  stage = 2,
  events = DEFAULT_EVENTS,
  courier = { name: "Maya Osei", detail: "Courier · Van 42", avatarUrl: "https://i.pravatar.cc/100?img=47" },
  from = "NORD Standard · Secaucus, NJ",
  to = "128 Linden St, Apt 4B, Brooklyn NY",
  items = DEFAULT_ITEMS,
  total = 628.0,
  currency = "$",
  onBack,
  onCallCourier,
  onMessageCourier,
  onHelp,
}: OrderTrackingScreenProps) {
  const insets = useSafeAreaInsets();

  return (
    <World primary="#65A30D">
    <SafeAreaView className="flex-1 bg-[#F4F5F9] dark:bg-[#111114]" edges={["top"]}>
      {/* Floating chrome — back disc + centered order pill. */}
      <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 {orderId}
            </Text>
          </View>
        </View>
      </View>

      <ScrollView
        className="flex-1"
        contentContainerClassName="gap-5 px-6"
        contentContainerStyle={{ paddingTop: insets.top + 60, paddingBottom: insets.bottom + 96 }}
        showsVerticalScrollIndicator={false}
      >
        {/* ETA hero — the one thing the user opened the screen for. */}
        <Mount>
          <Card variant="elevated" className="rounded-3xl bg-white dark:bg-[#1A1A20]">
            <Card.Content className="gap-4 p-5">
              <View>
                <Text variant="small" className="font-semibold">
                  {eta}
                </Text>
                <Text variant="muted" className="text-xs">
                  {etaDetail}
                </Text>
              </View>
              <Steps
                steps={stages}
                current={stage}
                variant="dots"
                labels
                interactive={false}
                haptic={false}
                accessibilityLabel={`Order status: ${stages[stage]}`}
              />
            </Card.Content>
          </Card>
        </Mount>

        {/* Event timeline — newest first. */}
        <Mount delay={80}>
          <Card variant="elevated" className="rounded-3xl bg-white dark:bg-[#1A1A20]">
            <Card.Content className="p-5">
              {events.map((e, i) => (
                <TimelineRow
                  key={e.label}
                  event={e}
                  done={!!e.time}
                  last={i === events.length - 1}
                />
              ))}
            </Card.Content>
          </Card>
        </Mount>

        {/* Courier — only while the order is actually moving. */}
        {courier ? (
          <Mount delay={140}>
            <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>
                  {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}

        {/* Delivery instruction — the courier-facing note every tracker has. */}
        <Mount delay={160}>
          <View className="flex-row items-center gap-2.5 rounded-2xl border border-dashed border-[#BEF04C] bg-[#EDF8C4] px-4 py-3 dark:border-[#BEF04C]/40 dark:bg-[#1E2410]">
            <Icon name="package" size="sm" color="#65A30D" />
            <Text variant="small" className="flex-1 text-xs">
              Leave at door — no signature needed
            </Text>
            <Text variant="small" className="font-medium text-[#65A30D]">
              Edit
            </Text>
          </View>
        </Mount>

        {/* Route — pickup → drop-off. */}
        <Mount delay={200}>
          <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="package" size="sm" color="mutedForeground" />
                </View>
                <Text variant="small" className="flex-1">
                  {from}
                </Text>
              </View>
              <View className="ml-4 h-4 w-px bg-border" />
              <View className="flex-row items-center gap-3">
                <View className="h-8 w-8 items-center justify-center rounded-lg bg-[#EDF8C4] dark:bg-[#1E2410]">
                  <Icon name="map-pin" size="sm" color="#65A30D" />
                </View>
                <Text variant="small" className="flex-1">
                  {to}
                </Text>
              </View>
            </Card.Content>
          </Card>
        </Mount>

        {/* Items strip + total. */}
        <Mount delay={260}>
          <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-2">
                {items.map((it, i) => (
                  <Image
                    key={`${it.name}-${i}`}
                    source={it.imageUrl ? { uri: it.imageUrl } : undefined}
                    rounded="xl"
                    aspectRatio={4 / 5}
                    className="w-12"
                    accessibilityLabel={`Photo of ${it.name}`}
                  />
                ))}
              </View>
              <Separator />
              <View className="flex-row items-center justify-between">
                <Text variant="muted">{items.length} items</Text>
                <Text variant="small" className="font-semibold tabular-nums">
                  {fmt(total, currency)}
                </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>
  );
}
OrderTrackingScreen.displayName = "OrderTrackingScreen";
agent prompt — paste into Claude Code, Cursor, Devin…
Recreate the "Order Tracking Screen" screen in React Native using LumioUI.

Goal: Delivery tracking — ETA hero with a stage progress bar, vertical event timeline, courier card with call/message actions, pickup-to-doorstep route, and an items strip 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 ecommerce-tracking
```

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

Native packages:
- @lumioui/ui@latest
- @lumioui/core@latest
- react-native-safe-area-context@*
- react-native-reanimated@*
- react-native-svg@*
- 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

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

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

### `image` — Cached image with placeholder, fallback and aspect handling.
- `<Image>` ×1

### `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>` ×13

## 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/ecommerce/tracking.tsx` exporting OrderTrackingScreen. 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 { Avatar, Button, Card, Glass, Icon, Image, Separator, Steps, Text, type IconName } from "@lumioui/ui";
import { cn } from "@lumioui/core";
import { catalogImg, LumioMark, Mount, Press, StickyBottomBar, World } from "../shared";

export interface TrackingEvent {
  label: string;
  /** "Today, 2:41 PM" — blank for events that haven't happened yet. */
  time?: string;
  icon?: IconName;
}

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

export interface OrderTrackingScreenProps {
  orderId?: string;
  /** Headline ETA — "Arriving Thursday, Sep 18". */
  eta?: string;
  etaDetail?: string;
  /** Horizontal stage labels — Ordered → Shipped → Out for delivery → Delivered. */
  stages?: string[];
  /** Index into `stages` of the current stage. */
  stage?: number;
  /** Vertical event log under the stage bar. */
  events?: TrackingEvent[];
  courier?: Courier;
  /** Pickup → destination rows. */
  from?: string;
  to?: string;
  items?: { name: string; imageUrl?: string }[];
  total?: number;
  currency?: string;
  onBack?: () => void;
  onCallCourier?: () => void;
  onMessageCourier?: () => void;
  onHelp?: () => void;
}

const img = (p: Parameters<typeof catalogImg>[0]) => catalogImg(p, 160, 200);

const DEFAULT_STAGES = ["Ordered", "Shipped", "Out for delivery", "Delivered"];

const DEFAULT_EVENTS: TrackingEvent[] = [
  { label: "Out for delivery", time: "Today, 9:12 AM", icon: "truck" },
  { label: "Arrived at local facility", time: "Today, 6:40 AM", icon: "package" },
  { label: "Departed regional hub", time: "Yesterday, 8:15 PM", icon: "package" },
  { label: "Picked up by courier", time: "Sep 15, 4:02 PM", icon: "package" },
  { label: "Order confirmed", time: "Sep 15, 11:30 AM", icon: "check-circle" },
];

const DEFAULT_ITEMS = [
  { name: "Structured Wool Overcoat", imageUrl: img("overcoat") },
  { name: "Garment-Dyed Tee", imageUrl: img("tee") },
  { name: "Heritage Graphic Tee", imageUrl: img("graphicTee") },
];

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

/** Vertical timeline row — icon dot, connector line, label + time.
 *  The last row drops the connector. */
function TimelineRow({
  event,
  done,
  last,
}: {
  event: TrackingEvent;
  done: boolean;
  last: boolean;
}) {
  return (
    <View className="flex-row gap-3" accessibilityElementsHidden={!done}>
      <View className="items-center">
        <View
          className={cn(
            "h-7 w-7 items-center justify-center rounded-full",
            done ? "bg-[#EDF8C4] dark:bg-[#1E2410]" : "bg-muted"
          )}
        >
          <Icon
            name={event.icon ?? "check"}
            size="sm"
            color={done ? "#65A30D" : "mutedForeground"}
          />
        </View>
        {!last ? <View className={cn("w-px flex-1", done ? "bg-[#BEF04C]" : "bg-border")} /> : null}
      </View>
      <View className="flex-1 pb-4">
        <Text variant="small" className={cn(done ? "font-semibold" : "text-muted-foreground")}>
          {event.label}
        </Text>
        {event.time ? (
          <Text variant="muted" className="text-xs tabular-nums">
            {event.time}
          </Text>
        ) : null}
      </View>
    </View>
  );
}
TimelineRow.displayName = "TimelineRow";

/** OrderTracking — ETA hero with the horizontal stage bar, vertical event
 *  timeline, courier card, route card, and the items strip. The delivery
 *  pattern every shipped-order app lands on. */
export function OrderTrackingScreen({
  orderId = "HL-2094",
  eta = "Arriving today",
  etaDetail = "Estimated between 4–6 PM",
  stages = DEFAULT_STAGES,
  stage = 2,
  events = DEFAULT_EVENTS,
  courier = { name: "Maya Osei", detail: "Courier · Van 42", avatarUrl: "https://i.pravatar.cc/100?img=47" },
  from = "NORD Standard · Secaucus, NJ",
  to = "128 Linden St, Apt 4B, Brooklyn NY",
  items = DEFAULT_ITEMS,
  total = 628.0,
  currency = "$",
  onBack,
  onCallCourier,
  onMessageCourier,
  onHelp,
}: OrderTrackingScreenProps) {
  const insets = useSafeAreaInsets();

  return (
    <World primary="#65A30D">
    <SafeAreaView className="flex-1 bg-[#F4F5F9] dark:bg-[#111114]" edges={["top"]}>
      {/* Floating chrome — back disc + centered order pill. */}
      <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 {orderId}
            </Text>
          </View>
        </View>
      </View>

      <ScrollView
        className="flex-1"
        contentContainerClassName="gap-5 px-6"
        contentContainerStyle={{ paddingTop: insets.top + 60, paddingBottom: insets.bottom + 96 }}
        showsVerticalScrollIndicator={false}
      >
        {/* ETA hero — the one thing the user opened the screen for. */}
        <Mount>
          <Card variant="elevated" className="rounded-3xl bg-white dark:bg-[#1A1A20]">
            <Card.Content className="gap-4 p-5">
              <View>
                <Text variant="small" className="font-semibold">
                  {eta}
                </Text>
                <Text variant="muted" className="text-xs">
                  {etaDetail}
                </Text>
              </View>
              <Steps
                steps={stages}
                current={stage}
                variant="dots"
                labels
                interactive={false}
                haptic={false}
                accessibilityLabel={`Order status: ${stages[stage]}`}
              />
            </Card.Content>
          </Card>
        </Mount>

        {/* Event timeline — newest first. */}
        <Mount delay={80}>
          <Card variant="elevated" className="rounded-3xl bg-white dark:bg-[#1A1A20]">
            <Card.Content className="p-5">
              {events.map((e, i) => (
                <TimelineRow
                  key={e.label}
                  event={e}
                  done={!!e.time}
                  last={i === events.length - 1}
                />
              ))}
            </Card.Content>
          </Card>
        </Mount>

        {/* Courier — only while the order is actually moving. */}
        {courier ? (
          <Mount delay={140}>
            <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>
                  {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}

        {/* Delivery instruction — the courier-facing note every tracker has. */}
        <Mount delay={160}>
          <View className="flex-row items-center gap-2.5 rounded-2xl border border-dashed border-[#BEF04C] bg-[#EDF8C4] px-4 py-3 dark:border-[#BEF04C]/40 dark:bg-[#1E2410]">
            <Icon name="package" size="sm" color="#65A30D" />
            <Text variant="small" className="flex-1 text-xs">
              Leave at door — no signature needed
            </Text>
            <Text variant="small" className="font-medium text-[#65A30D]">
              Edit
            </Text>
          </View>
        </Mount>

        {/* Route — pickup → drop-off. */}
        <Mount delay={200}>
          <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="package" size="sm" color="mutedForeground" />
                </View>
                <Text variant="small" className="flex-1">
                  {from}
                </Text>
              </View>
              <View className="ml-4 h-4 w-px bg-border" />
              <View className="flex-row items-center gap-3">
                <View className="h-8 w-8 items-center justify-center rounded-lg bg-[#EDF8C4] dark:bg-[#1E2410]">
                  <Icon name="map-pin" size="sm" color="#65A30D" />
                </View>
                <Text variant="small" className="flex-1">
                  {to}
                </Text>
              </View>
            </Card.Content>
          </Card>
        </Mount>

        {/* Items strip + total. */}
        <Mount delay={260}>
          <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-2">
                {items.map((it, i) => (
                  <Image
                    key={`${it.name}-${i}`}
                    source={it.imageUrl ? { uri: it.imageUrl } : undefined}
                    rounded="xl"
                    aspectRatio={4 / 5}
                    className="w-12"
                    accessibilityLabel={`Photo of ${it.name}`}
                  />
                ))}
              </View>
              <Separator />
              <View className="flex-row items-center justify-between">
                <Text variant="muted">{items.length} items</Text>
                <Text variant="small" className="font-semibold tabular-nums">
                  {fmt(total, currency)}
                </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>
  );
}
OrderTrackingScreen.displayName = "OrderTrackingScreen";
```

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