# Plan gate

A panel for a feature the current plan doesn't include, honestly empty: the feature's name, which plan includes it, what the plan lacks, what the feature would show (as a list of words, with no sample data behind it), and how to get it: the app's upgrade action, or who to ask. The feature's own controls, named in `controls`, stand in their place through `Locked`, saying which plan they need. With `upgradeLocked`, the upgrade button stays, locked, saying why (only an owner can change the plan, say).

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

## Install

```bash
npx candor-ui add plan-gate
```

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

## Example

```tsx
"use client"

import { PlanGate } from "@/components/candor/plan-gate"

export default function Example() {
  // Shown where the feature would be: what it would show is words, never sample figures.
  return (
    <PlanGate
      className="max-w-lg"
      feature="Release readiness"
      plan="Pro"
      currentPlan="Starter"
      description="What has to happen before each release, checked against your environments."
      shows={["Each change’s risk and who approved it", "Tests and checks still to pass", "What a rollback would undo"]}
      controls={["Run a readiness check"]}
      onUpgrade={() => {}}
    />
  )
}
```

## <PlanGate>

Props:

- `feature: string`: The feature's name, e.g. "Release readiness".
- `plan: string`: The plan that includes it, e.g. "Pro".
- `currentPlan?: string | undefined`: The plan the account is on now, e.g. "Starter". Left out, the panel says only that the plan doesn't include it.
- `description?: string | undefined`: What the feature is for, in one line, in the app's words.
- `shows?: string[] | undefined` (default `[]`): What the feature would show, as words: "Each change's risk", "What has to happen before the release".
- `controls?: string[] | undefined` (default `[]`): The feature's own controls, by their labels, drawn in their place as locked buttons that say which plan they need.
- `onUpgrade?: (() => void) | undefined`: Shows the upgrade button; called when it's pressed. Without it, the panel says who to ask.
- `upgradeLabel?: string | undefined`: The upgrade button's words; "Upgrade to {plan}" by default.
- `upgradeLocked?: string | undefined`: Why this person can't upgrade, e.g. "Only the account owner can change the plan." The button stays, locked, saying it.
- `className?: string | undefined`: Classes, merged with Candor's.

## Strings (`planGate`)

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

- `includedIn`: Included in {plan}
- `lacks`: Your plan, {current}, doesn’t include {feature}.
- `lacksUnnamed`: Your plan doesn’t include {feature}.
- `shows`: What it shows
- `empty`: Nothing is shown here until {feature} is part of your plan: no sample data stands in for it.
- `upgrade`: Upgrade to {plan}
- `howToGet`: Ask whoever manages your plan to move to {plan}.
- `controlLocked`: {feature} is included in {plan}. Your plan doesn’t include it.

## 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`: its fixed strings in `strings`, its nouns in `nouns`; entity kinds and agent roles in `EntityKindsProvider` and `AgentRolesProvider`.
