# Courier Card

> A courier row for dispatch screens - avatar, availability, vehicle, distance and ETA from the pickup, cash float and active orders, with a selectable list wrapper.

Source: https://docs.nasaqui.com/components/courier-card

## Install

```bash
npx shadcn@latest add https://docs.nasaqui.com/r/courier-card.json
```

One courier as a compact card, so a dispatcher can compare who is closest, free and carrying cash. `CourierList` stacks
cards as a single-select listbox for assigning an order.

## When to use

- Picking a courier for an order in a dispatch console.
- Showing the assigned courier in an order drawer.

## When not to use

- Tabular fleet reporting: use [`DataTable`](https://docs.nasaqui.com/components/data-table).
- The courier a customer sees while tracking: use [`DeliveryTracker`](https://docs.nasaqui.com/components/delivery-tracker).

## Import

```tsx
import { CourierCard, CourierList } from "@fadymondy/nasaq/web";
// inside this monorepo: "@nasaq/web"
```

## Quick start

```tsx
<CourierList
  couriers={[{ id: "c1", name: "Omar Haddad", nameAr: "عمر حداد", status: "available", vehicle: "motorbike", distanceMeters: 850, etaSeconds: 240, cashFloatMinor: 25000 }]}
  selectedId={id}
  onSelectCourier={setId}
/>
```

## Anatomy

```
CourierList  data-slot="courier-list"
└─ CourierCard  data-slot="courier-card"  data-status data-selected
   ├─ Avatar + status dot
   ├─ name, vehicle
   ├─ distance · ETA · cash float · active orders
   └─ actions slot
```

## API

### CourierCard

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `name` / `nameAr` | `string` | required / none | Name; the Arabic one is used in `ar`. |
| `avatarSrc` | `string` | none | Photo; initials otherwise. |
| `status` | `"available" \| "busy" \| "offline"` | `"available"` | Availability badge and dot. |
| `vehicle` | `"bike" \| "motorbike" \| "car" \| "van" \| "walk"` | none | Vehicle icon and label. |
| `vehicleDetail` | `string` | none | Plate or model. |
| `distanceMeters` | `number` | none | Distance from the pickup. |
| `etaSeconds` | `number` | none | Time to reach the pickup. |
| `cashFloatMinor` | `number` | none | Cash the courier holds, in minor units. |
| `activeOrders` | `number` | none | Orders in progress. |
| `currency` | `string` | `"USD"` (`"SAR"` in Arabic) | ISO currency for the float. |
| `selected` / `onSelect` | `boolean` / `() => void` | none | Selection; makes the card a button. |
| `actions` | `ReactNode` | none | Trailing slot, for example an Assign button. |
| `compact` | `boolean` | `false` | Tighter layout. |
| `locale` / `labels` | `"en" \| "ar"` / partial strings | context | Language and overrides. |

### CourierList

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `couriers` | `(CourierCardProps & { id: string })[]` | required | Couriers to list. |
| `selectedId` | `string \| null` | none | Selected courier. |
| `onSelectCourier` | `(id: string) => void` | none | Selection callback. |
| `locale` / `labels` | as above | context | Language and overrides. |

## Examples

See the lab stories: list with selection, single, compact, other currency and Arabic.

## Accessibility

| Key | Action |
| --- | --- |
| `Tab` | Moves to the next selectable card. |
| `Enter` / `Space` | Selects the card. |

Status is text as well as colour. The selected card carries `aria-pressed`.

## RTL & i18n

Layout uses logical properties. Arabic names, labels and units are built in; numbers and the currency follow the locale.

## Styling & tokens

Uses `--status-*` tokens for the dot and `--brand` for the selected ring. Target `[data-status]` and `[data-selected]`.

## Do / Don't

- Do sort the list by ETA before rendering.
- Don't hide the cash float; dispatchers rely on it.

## Related

[`DispatchOffer`](https://docs.nasaqui.com/components/dispatch-offer), [`RouteStops`](https://docs.nasaqui.com/components/route-stops), [`MapView`](https://docs.nasaqui.com/components/map-view).

## Lab

https://docs.nasaqui.com/?path=/docs/components-delivery-courier-card--docs

## Code

### React

```tsx
<CourierList
  couriers={[{ id: "c1", name: "Omar Haddad", nameAr: "عمر حداد", status: "available", vehicle: "motorbike", distanceMeters: 850, etaSeconds: 240, cashFloatMinor: 25000 }]}
  selectedId={id}
  onSelectCourier={setId}
/>
```

### shadcn

```tsx
<CourierList
  couriers={[{ id: "c1", name: "Omar Haddad", nameAr: "عمر حداد", status: "available", vehicle: "motorbike", distanceMeters: 850, etaSeconds: 240, cashFloatMinor: 25000 }]}
  selectedId={id}
  onSelectCourier={setId}
/>
```

### Vue

```vue
<script setup lang="ts">
import { NqCourierList } from "@fadymondy/nasaq/vue";
import { ref } from "vue";

const id = ref<string | null>("c1");
const couriers = [
  { id: "c1", name: "Omar Haddad", nameAr: "عمر حداد", status: "available", vehicle: "motorbike", distanceMeters: 850, etaSeconds: 240, cashFloatMinor: 25000 },
] as const;
</script>

<template>
  <NqCourierList v-model:selected-id="id" :couriers="couriers" />
</template>
```

### Blade

```blade
<x-nq::courier-card.list
    selectable
    selected-id="c1"
    :couriers="[['id' => 'c1', 'name' => 'Omar Haddad', 'nameAr' => 'عمر حداد', 'status' => 'available', 'vehicle' => 'motorbike', 'distanceMeters' => 850, 'etaSeconds' => 240, 'cashFloatMinor' => 25000]]"
/>
```

### HTML + Alpine

```html
<ul role="list" data-slot="courier-list" aria-label="Couriers" class="flex flex-col gap-2">
            <li>
            <div data-slot="courier-card" data-status="available"  data-selected     
    class="ring-2 ring-primary/30 flex items-center gap-2 rounded-card border bg-card p-3 transition-colors duration-150 ease-nq border-primary">
    <button
                    type="button" aria-pressed="true" aria-label="Omar Haddad, Available, selected"
            x-on:click="$dispatch('nq-select', { id: 'c1' })"
            class="flex min-w-0 flex-1 cursor-pointer items-center gap-3 rounded-control text-start outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus"
            >
        <span class="relative shrink-0">
            <span data-slot="avatar" x-data="nqAvatar(0)"
    class="inline-flex shrink-0 select-none items-center justify-center overflow-hidden bg-secondary align-middle font-medium text-secondary-foreground size-10 text-label rounded-full">
                    <span data-slot="avatar-fallback" class="flex size-full items-center justify-center" x-bind="fallback"
             role="img" aria-label="Omar Haddad" >OH</span>
    </span>
            <span data-slot="courier-dot" aria-hidden="true" class="absolute -bottom-0.5 -end-0.5 size-3 rounded-full ring-2 ring-card bg-nq-success"></span>
        </span>
        <span class="flex min-w-0 flex-1 flex-col gap-0.5 text-start">
            <span class="flex min-w-0 items-center gap-2">
                <bdi dir="auto" class="truncate text-label text-foreground">Omar Haddad</bdi>
                <span data-slot="courier-status" class="shrink-0 text-caption text-nq-success-text">Available</span>
            </span>
                            <span class="flex flex-wrap items-center gap-x-3 gap-y-0.5 text-body-sm text-muted-foreground">
                                            <span class="inline-flex items-center gap-1">
                            <svg aria-hidden="true" class="size-3.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="m18 14-1-3"/>
  <path d="m3 9 6 2a2 2 0 0 1 2-2h2a2 2 0 0 1 1.99 1.81"/>
  <path d="M8 17h3a1 1 0 0 0 1-1 6 6 0 0 1 6-6 1 1 0 0 0 1-1v-.75A5 5 0 0 0 17 5"/>
  <circle cx="19" cy="17" r="3"/>
  <circle cx="5" cy="17" r="3"/>
</svg>                            <span>Motorbike</span>
                                                    </span>
                                                                <span><bdi class="tabular-nums">850 m</bdi> away</span>
                                                                <span>ETA <bdi class="tabular-nums">4 min</bdi></span>
                                    </span>
                                    <span class="flex flex-wrap items-center gap-x-3 gap-y-0.5 text-caption text-muted-foreground">
                                                    <span class="inline-flex items-center gap-1">
                                <svg aria-hidden="true" class="size-3.5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M11 15h2a2 2 0 1 0 0-4h-3c-.6 0-1.1.2-1.4.6L3 17"/>
  <path d="m7 21 1.6-1.4c.3-.4.8-.6 1.4-.6h4c1.1 0 2.1-.4 2.8-1.2l4.6-4.4a2 2 0 0 0-2.75-2.91l-4.2 3.9"/>
  <path d="m2 16 6 6"/>
  <circle cx="16" cy="9" r="2.9"/>
  <circle cx="6" cy="5" r="3"/>
</svg>                                <span>Cash float</span>
                                <bdi class="tabular-nums text-foreground">$250.00</bdi>
                            </span>
                                                                    </span>
                                    </span>
    </button>
    </div>
        </li>
    </ul>
```
