@get-asset/sdk
Book Health
Headless compound answering “are my books healthy?” for one fiscal year of the business (twelve months from its fiscal-year start; calendar years when that is January): a fraction of months closed and verified (the denominator is always 12), a per-month tone for a twelve-month grid and meter, and the open tasks waiting on the business, grouped by category. Selecting a month filters the tasks to it; the in-scope list is handed to a nested Tasks compound, actions included. A year dropdown offers previous years back to the business's entries start, and hides when there are none — the component is deliberately decoupled from the AssetProvider's shared date range.
Anatomy
Import the primitive and compose the parts you need.
<BookHealth.Root><BookHealth.YearSelect>{/* a Select-Root-shaped child */}</BookHealth.YearSelect><BookHealth.Success><BookHealth.ReadyCount /> / <BookHealth.MonthCount /><BookHealth.Months><BookHealth.MonthTone /> {/* meter segment */}</BookHealth.Months><BookHealth.Months><BookHealth.MonthCell><BookHealth.MonthLabel /><BookHealth.MonthTaskCount /></BookHealth.MonthCell><BookHealth.MonthBreakdown><BookHealth.BreakdownLabel /><BookHealth.BreakdownCount /></BookHealth.MonthBreakdown><BookHealth.BreakdownTotal /></BookHealth.Months><BookHealth.TasksLabel /><BookHealth.TaskCount /><BookHealth.ShowAllMonths /><BookHealth.TasksEmpty><BookHealth.TasksEmptyMessage /></BookHealth.TasksEmpty>{/* The in-scope tasks render through the Tasks compound: */}{/* <Tasks.Root tasks={tasks} onUpload={uploadTask} onAddNote={addTaskNote}> ... */}</BookHealth.Success></BookHealth.Root>
Required scopes
The access token used by AssetProvider must include these scopes for this primitive to fetch data successfully:
business:readrequest:readplaid:createdocument:createjournal_entry:readjournal_entry:create
API reference
Root props
| Prop | Type | Default | Description |
|---|---|---|---|
months | BookHealthMonthData[] | — | Override fetched months (skips every API fetch). Each entry is { month: 'YYYY-MM', status, tasks? } — tasks ride on their month. |
entriesStart | string | — | Override the business's entries_start date (YYYY-MM-DD), which decides the fiscal years the picker offers. The picker hides when there are no previous years. |
fiscalYearStart | string | — | Override the business's fiscal-year start anchor (MM/DD), which decides where each twelve-month window begins. Defaults to the business's fiscal_year; January when unknown. With entriesStart, providing it skips the business fetch. |
state | "loading" | "error" | "empty" | — | Force a specific state for testing. |
locked | boolean | — | Gate the card for an unentitled viewer. Activates the Locked state and skips every API fetch. See /docs/sdk/locked-upsell. |
upsell | { title?, description?, ctaLabel?, onUpgrade? } | — | Locked-state copy + upgrade handler; merged field-by-field over the card's default copy, then the generic fallback. |
onReviewTask | (task: TasksTask) => void | — | Hand a month-level review task off to your transactions page for its month; exposed on the context for the nested task list. The hand-off button is a no-op while unset. |
childrenrequired | ReactNode | — | Compound parts. |
Parts
Container
Always rendered. Provides data and context to its children.
| Part | Description |
|---|---|
BookHealth.Root | Fetches the year's books status, the pending tasks, and the business (for the year-picker floor), and provides context. |
BookHealth.YearasChild? | The year on display, as text. Sets data-year. |
BookHealth.YearSelect | Wires the year to a Select-Root-shaped child (injects value + onValueChange). Renders nothing when there are no previous years to switch to. |
BookHealth.YearItems | Iterates the selectable years (newest first) with per-year context. |
BookHealth.YearItemasChild? | Renders one selectable year. Injects value and the year's label. |
Success
Renders when the year has data.
| Part | Description |
|---|---|
BookHealth.Success | State wrapper. Compose the card's UI inside. |
BookHealth.ReadyCountasChild?, format? | Months closed and verified — the fraction's numerator. |
BookHealth.MonthCountasChild?, format? | The fraction's denominator: always 12. |
BookHealth.Months | Iterates the twelve months in calendar order with per-month context. Compose it once for the month grid and again for the meter. |
BookHealth.MonthCellasChild? | One month cell (a button). Clicking selects the month and filters the task list; clicking again clears. Sets data-tone, data-selected, data-current. |
BookHealth.MonthToneasChild? | A bare element carrying the month's data-tone and data-current — the meter segment, or any tone-coloured wrapper. |
BookHealth.MonthLabelasChild? | The month's short label ("Jun"). Sets data-tone and data-current. |
BookHealth.MonthTaskCountasChild?, format? | The month's open-task count — the count chip's number. Caps at "20+" by default. |
BookHealth.MonthClosedMessageasChild? | Renders only for a closed month; defaults to the copy "Closed and verified". |
BookHealth.MonthBreakdown | Iterates the month's non-empty task buckets with per-row context — the hover snapshot's rows. |
BookHealth.BreakdownLabelasChild? | One bucket's label ("Transactions to review"). Sets data-group. |
BookHealth.BreakdownCountasChild?, format? | One bucket's count for the month. |
BookHealth.BreakdownTotalasChild?, format? | The month's total open tasks — the breakdown's Total row value. |
BookHealth.TasksLabelasChild? | "Open tasks", or "{Month} tasks" while a month is selected. |
BookHealth.TaskCountasChild?, format? | Open tasks in scope — the selected month's, or the whole year's. Sets data-empty at zero. |
BookHealth.ShowAllMonthsasChild? | Button clearing the month selection. Renders nothing while no month is selected. |
BookHealth.TasksEmptyasChild? | Renders its children only when the tasks section has nothing to list. Sets data-kind (year-clear / month-clear / month-not-started) and data-tone (success / neutral). |
BookHealth.TasksEmptyMessageasChild? | The notice copy: "Nothing is waiting on you." / "{Month} is all caught up." / "{Month} hasn't started yet." |
context.tasks / uploadTask / addTaskNote | The in-scope tasks plus the completion callbacks, via useBookHealth() — hand them to a nested Tasks list (tasks / onUpload / onAddNote) and the card re-syncs after each action. |
Loading
Renders while the fetches are in flight.
| Part | Description |
|---|---|
BookHealth.Loading | State wrapper. The Months iterator still yields the twelve padded months, so a loading grid can render plain labels. |
Empty
Renders when the API has no months for the year.
| Part | Description |
|---|---|
BookHealth.Empty | State wrapper. Render an empty-state message inside. |
Error
Renders on fetch error (the business lookup never errors the card).
| Part | Description |
|---|---|
BookHealth.Error | State wrapper. Compose the error UI inside. |
BookHealth.ErrorMessageasChild? | Renders the error message string. |
BookHealth.RetryasChild? | Button that re-runs the fetches. |
Locked
Renders when `locked` is set — the viewer isn't entitled to the card. Mutually exclusive with the other states, and no data is fetched; the Months iterator yields a deterministic teaser.
| Part | Description |
|---|---|
BookHealth.Locked | State wrapper. Compose the upgrade / upsell UI inside — see LockedUpsell. |
Unlocked
Renders whenever the card is NOT locked — the inverse of Locked.
| Part | Description |
|---|---|
BookHealth.Unlocked | State wrapper. Renders children whenever the card isn't locked. |
Hooks
| Part | Description |
|---|---|
useBookHealth() | Hook returning the full context: year, years, setYear, months, readyCount, selectedMonth, selectMonth, taskCount, tasks, uploadTask, addTaskNote, noticeKind, and the state flags. |
useBookHealthMonth() | Inside Months: the current month — tone, label, name, counts, per-bucket groupCounts. |