# Invite chooser

Shown at sign-in when more than one account has invited you. Pick one to join; the others are superseded and will show as expired. Or create your own account instead, which supersedes them all. Nothing happens until you choose.

- Registry name: `invite-chooser` (`@candor/invite-chooser`)
- 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/invite-chooser

## Install

```bash
npx candor-ui add invite-chooser
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/invite-chooser`.
It brings in: button, locale, relative-time, utils.
npm packages: lucide-react@^1.67.0.

## Example

```tsx
"use client"

import { InviteChooser, type IncomingInvite } from "@/components/invite-chooser"

const inDays = (d: number) => new Date(Date.now() + d * 86_400_000).toISOString()

const invites: IncomingInvite[] = [
  { id: "inv-1", account: "Acme", invitedBy: "Priya", grants: ["Contributor on Acme API Staging"], expiresAt: inDays(5) },
  { id: "inv-2", account: "Acme Labs", invitedBy: "Dana", grants: [], expiresAt: inDays(1) },
]

export default function Example() {
  // Nothing is chosen until the person picks an invite.
  return <InviteChooser invites={invites} onJoin={() => {}} onCreateOwn={() => {}} />
}
```

## <InviteChooser>

Props:

- `invites: IncomingInvite[]`: The invites waiting for this person, one per account.
- `onJoin: (id: string) => void`: Called with the chosen invite's id when the person joins.
- `onCreateOwn?: (() => void) | undefined`: Shows a link to create their own account instead; called when it's clicked.
- `busy?: boolean | undefined` (default `false`): Disables Join while it's being recorded.
- `className?: string | undefined`

## Strings (`inviteChooser`)

The fixed words, English by default. Override any of them under `inviteChooser` in `<LocaleProvider strings={{ inviteChooser: { … } }}>`; the table is exported as `inviteChooserStrings`.

- `heading`: { one: "{count} account has invited you", other: "{count} accounts have invited you" }
- `belongToOne`: { one: "You can belong to one. Joining it supersedes the other invite.", other: "You can belong to one. Joining it supersedes the other invites.", }
- `from`: From {name} · expires {expires}
- `noRoles`: No roles yet
- `join`: Join {account}
- `choose`: Choose an account
- `createOwn`: Create my own account instead

## Types

### IncomingInvite

```ts
{ id: string account: string invitedBy: string /** What joining gives, e.g. ["Editor on Shop staging"]. */ grants: string[] expiresAt: string }
```

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