# useArrivals

Calls `onNew` with the ids that weren't there before: the way to raise a sound or a signal from data, never from a mount. The ids present at the first render are the ones that were already waiting when the page drew, so they are not news and `onNew` is never called for them. After that, each render that brings an id the hook hasn't seen calls `onNew` once with all the new ids together (a burst is one call), and an id that goes away and comes back is new again. Feed it what the service reports, such as the adapters' waiting approvals or finished runs; don't feed it what a component renders.

const attention = useAttention({ sound: { enabled } }) useArrivals(waiting.map((a) => a.id), () => attention.signal({ kind: "approval", title: "An approval is waiting" }))

- Registry name: `use-arrivals` (`@candor/use-arrivals`)
- Tier: Pro. Installing it needs a Pro, Premium or Team licence key: the person runs `npx candor-ui key <key>` themselves; never ask for the key in chat or write it to a file.
- Docs: https://candor.themethodic.com/docs/use-arrivals

## Install

```bash
npx candor-ui add use-arrivals
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/use-arrivals`.

## Example

```tsx
"use client"

import * as React from "react"
import { useArrivals } from "@/lib/use-arrivals"
import { Button } from "@/components/ui/button"

/*
 * Two approvals were already waiting when this example drew, so they are not news and nothing is announced for them.
 * Press the button and a third arrives from "the service": that id wasn't there before, so the callback runs once.
 * Feed the hook what a service reports, never what a component renders, so a page load or a re-render stays quiet.
 */
export default function Example() {
  const [waiting, setWaiting] = React.useState(["approve-batch-size", "approve-export"])
  const [heard, setHeard] = React.useState<string[]>([])
  useArrivals(waiting, (ids) => setHeard((h) => [...h, ...ids]))
  return (
    <div className="flex flex-col items-start gap-3 text-sm">
      <p>
        Waiting on you: <strong>{waiting.length}</strong>. Announced as new: <strong>{heard.length}</strong>
        {heard.length > 0 && <> ({heard.join(", ")})</>}.
      </p>
      <Button size="sm" variant="outline" onClick={() => setWaiting((w) => [...w, `approve-${w.length + 1}`])}>
        A new approval arrives
      </Button>
    </div>
  )
}
```

## Functions

### useArrivals

```ts
useArrivals(ids: readonly string[], onNew: (ids: string[]) => void)
```

## Rules for using Candor UI

- Components take plain typed data. Never pass model output as HTML or render it as a link; messages are typed blocks.
- A control that can't be used says why: wrap it in `<Locked reason="…">`, don't just disable it.
- Don't show a value you don't have: leave it out (it renders as —) rather than guess. An estimate is labelled as one.
- Nothing is pre-selected in a decision a person makes, and the agent is named from your app's data, never from model output.
- Your app's words go in `LocaleProvider` (fixed strings) and `TermsProvider` (nouns); entity kinds and agent roles in `EntityKindsProvider` and `AgentRolesProvider`.
