# Spend Flow

> Workload traffic converging on a meter that prices every call, then fanning out to a card of nested budgets, where each call rolls up to a service, its environment, and its project, and every level's spend counts up as a pulse reaches it.

Source: https://ui.cortexcn.dev/docs/cortex/spend-flow

## Installation

```bash
npx shadcn@latest add @cortexcn/spend-flow
```

## Usage

```tsx
import { SpendFlow } from "@/components/spend-flow";
```

```tsx
<SpendFlow
  title="Cloud spend"
  levels={[
    { kind: "Project", name: "Atlas", spent: 642.1, budget: 900 },
    { kind: "Environment", name: "Production", spent: 271.35, budget: 300 },
    { kind: "Service", name: "Search API", spent: 46.8, budget: 60 },
  ]}
/>
```

Each level is counted against the one above it, so the card steps in one level at a time and joins them with a tree line. Use it for cloud costs, an API that bills per call, or any product that meters usage against budgets at more than one level.

## Examples

### Over budget

A level that spends past its budget turns its marker, amount, and bar to the destructive color. While the flow is live, a level close to its limit can cross it as pulses arrive.

### Static

With `animated={false}`, nothing moves and the numbers stay as given.

## Behavior

- While the flow is on screen, pulses run from the left into the meter, then on to each level. The numbers count up from zero, then each level adds its `perCall` every time a pulse reaches it, and the call count under the source label goes up as pulses reach the meter.
- Each bar has `segments` cells. The spent share fills from the left and brightens toward the newest spend.
- With reduced motion enabled, or off screen, nothing moves and every number shows its given value.
- The whole flow is one SVG that scales to its container. It lays out at `minWidth` or wider (560px by default); in a narrower container it scrolls sideways and takes keyboard focus so it can be scrolled from the keyboard.
- Amounts are written with `Intl.NumberFormat` in `locale` and `currency`: what was spent to the cent, the budget in whole units.
- Screen readers hear one summary: where the traffic goes, then each level's spend and budget, and which levels are over.
- The caption in the corner says the numbers are illustrative. Change it when the flow shows real data.

## Props

### SpendFlow

| Prop             | Type               | Default                                | Description                                            |
| ---------------- | ------------------ | -------------------------------------- | ------------------------------------------------------ |
| `levels`         | `SpendFlowLevel[]` | Three sample levels                    | The levels one call is counted against, widest first   |
| `title`          | `string`           | `"Cloud spend"`                        | The card's title                                       |
| `gatewayName`    | `string`           | `"Meter"`                              | The name in the middle node                            |
| `gatewayCaption` | `string`           | `"Prices every call, checks budgets"`  | A line under the middle node                           |
| `sourceLabel`    | `string`           | `"Workload traffic"`                   | The label over the incoming lines                      |
| `calls`          | `number`           | `12840`                                | Calls counted so far, shown under the source label     |
| `callsLabel`     | `string`           | `"calls today"`                        | The words after the call count                         |
| `apiLabel`       | `string`           | `"Billing API"`                        | The label on the lines into the card                   |
| `note`           | `string`           | `"Each call counts at every level."`   | A note at the foot of the card                         |
| `caption`        | `string`           | `"Illustrative numbers"`               | A small label in the bottom-left corner                |
| `currency`       | `string`           | `"USD"`                                | An ISO 4217 code for the amounts                       |
| `locale`         | `string`           | `"en-US"`                              | The locale numbers are written in                      |
| `lines`          | `number`           | `22`                                   | How many lines of traffic come in from the left        |
| `segments`       | `number`           | `24`                                   | How many segments each budget bar has                  |
| `accent`         | `string`           | `"var(--foreground)"`                  | Color of the pulses, markers, and spent segments       |
| `animated`       | `boolean`          | `true`                                 | Run the pulses and count the numbers up while on screen |
| `minWidth`       | `number`           | `560`                                  | Narrowest layout width in pixels; below it, scroll     |
| `ariaLabel`      | `string`           | `"Spend flow"`                         | Names the flow for screen readers                      |
| `className`      | `string`           | -                                      | Extra classes on the frame                             |

### SpendFlowLevel

| Prop      | Type     | Default            | Description                                               |
| --------- | -------- | ------------------ | --------------------------------------------------------- |
| `kind`    | `string` | -                  | What the level is, such as `"Environment"`                |
| `name`    | `string` | -                  | Its name, such as `"Production"`                          |
| `spent`   | `number` | -                  | Spent so far, in `currency`                               |
| `budget`  | `number` | -                  | The limit, in `currency`                                  |
| `perCall` | `number` | A 400th of `budget` | Added each time a pulse reaches the level while it is live |