@get-asset/sdk

Receipts Config

One business's own receipt-request rule: the ReceiptsThreshold row, and a Save that commits it. This is the business-scoped half of the pair — GlobalReceiptsConfig is what the tenant sets for every business it has; this is what one business sets for itself, and it supersedes the global rule for that business alone. Reads GET /v0/business/{id}/rules/receipts and writes it back with PATCH.

Preview

Loading preview…

Anatomy

Import the primitive and compose the parts you need.

<ReceiptsConfig.Root
title="Auto-request Receipts"
subtitle="You'll be asked for a receipt on anything over this amount."
onSaveSuccess={() => toast("Receipt settings saved")}
>
<ReceiptsConfig.Loading></ReceiptsConfig.Loading>
<ReceiptsConfig.Error>
<ReceiptsConfig.ErrorMessage />
<ReceiptsConfig.Retry />
</ReceiptsConfig.Error>
<ReceiptsConfig.Success>
{/* The row is a ReceiptsThreshold.Root — compose its parts inside. */}
<ReceiptsConfig.Threshold>
<ReceiptsThreshold.Title />
<ReceiptsThreshold.Subtitle />
<ReceiptsThreshold.Field>
<ReceiptsThreshold.Currency />
<ReceiptsThreshold.Amount />
</ReceiptsThreshold.Field>
<ReceiptsThreshold.Toggle />
</ReceiptsConfig.Threshold>
<ReceiptsConfig.NotConfigured></ReceiptsConfig.NotConfigured>
</ReceiptsConfig.Success>
<ReceiptsConfig.SaveErrorMessage />
<ReceiptsConfig.Save />
</ReceiptsConfig.Root>

Required scopes

The access token used by AssetProvider must include these scopes for this primitive to fetch data successfully:

  • business:read
  • business:update

API reference

Root props

PropTypeDefaultDescription
titlerequiredstringThe row's label, e.g. "Auto-request Receipts".
subtitlerequiredstringThe line under the label explaining what the threshold does.
currencystringISO-4217 code the threshold is denominated in. Resolved from the business's own country when omitted — a Canadian business's threshold is in CAD — which costs a Business lookup the basis-aware components already make, so a screen holding both pays for one.
settingReceiptsConfigSettingOverride the fetched rule, skipping the request entirely: { amount, enabled }. For storybook, tests, or a host that already holds the setting.
state"loading" | "error" | "not-configured"Force a state, skipping the request — storybook/tests.
saveErrorErrorForce the save-error state — storybook/tests. A real one only appears after a failed write.
onSave(setting: ReceiptsConfigSetting) => void | Promise<void>Own the write. Called with the edited rule when Save is pressed, instead of the built-in PATCH — return a promise and the card shows its saving state until it settles, and reports a rejection through SaveError.
onSaveSuccess(setting: ReceiptsConfigSetting) => voidCalled after a save succeeds — whichever path wrote it — with the rule as saved: the server-confirmed values when the card wrote, the submitted ones when onSave did.
onSaveError(error: Error) => voidCalled when a save fails, with the same error SaveError renders.
savingbooleanForce the saving state — storybook/tests. Otherwise it follows the write in flight.
disabledbooleanMake the whole card inert (e.g. the viewer can't change the setting).
editablebooleanWhether the setting can be changed here. Defaults to true; pass false and the controls go inert and Save isn't rendered at all. Different from disabled, which keeps the button on screen but unpressable — that says “not now”, this says “not here”.
saveLabelstringOverride the copy on the save button. Defaults to "Save".

Parts

State wrappers

Loading, Error and Success are mutually exclusive. NotConfigured sits inside the loaded state, and Dirty / Saving / SaveError are about the write.

PartDescription
ReceiptsConfig.LoadingRendered while the business's rule is being read.
ReceiptsConfig.ErrorRendered when the read failed. A 404 is not a failure — see NotConfigured. Compose ErrorMessage and Retry inside.
ReceiptsConfig.SuccessRendered once the rule has landed — hold the row in here.
ReceiptsConfig.NotConfiguredRendered while this business has never had a rule saved. The row still renders, reading off at 0 — which is the rule in force — so this only marks that it was never set explicitly.
ReceiptsConfig.DirtyRendered while the draft differs from what the business has saved.
ReceiptsConfig.SavingRendered only while a save is in flight.
ReceiptsConfig.SaveErrorRendered when the last save failed. Distinct from Error: a failed write still has a row on screen and a draft worth keeping.

Parts

PartDescription
ReceiptsConfig.ThresholdWraps its children in a ReceiptsThreshold.Root fed from this card's draft — so the row is the ReceiptsThreshold compound, composed with its own parts, and its edits land here instead of going straight to you. The row is disabled while the card is disabled or saving.
ReceiptsConfig.ErrorMessage
asChild?, format?
The read-failure copy. Defaults to the standard “We couldn't load your receipt settings…” line.
ReceiptsConfig.Retry
asChild?
Refetches the business's rule. Renders a button unless slotted.
ReceiptsConfig.SaveErrorMessage
asChild?, format?
The failed-write copy. Renders nothing when the last save didn't fail, so it can stand on its own without SaveError around it.
ReceiptsConfig.Save
asChild?
Writes the draft — the built-in PATCH, or your onSave. Disabled until there is something to save: an untouched rule, a save in flight, a failed read, or a disabled card all leave it inert. A card that is not editable renders no button at all. Prints "Save" unless you pass a saveLabel or your own children.

Hooks

PartDescription
useReceiptsConfig()Hook returning { title, subtitle, currency, amount, enabled, notConfigured, loading, error, retry, dirty, saving, saveError, disabled, canSave, saveLabel, setAmount, setEnabled, save }. Throws when used outside <ReceiptsConfig.Root>.

When no rule was ever set

A business that hasn't set its own rule has no config to read: the API answers 404. That is a state of this card, not a failure — Error stays closed and NotConfigured opens, for a host that wants to say the rule has never been set.

No row means no receipts are requested, so the card reads off at a threshold of 0 — not a placeholder, but the rule in force until one is saved. Save waits for a change, as it does everywhere else: the first one writes the rule, and from then on NotConfigured closes.

Telling that 404 from a real failure needs the response status, which the generated client doesn't put on what it throws — the SDK attaches it, so Error can stay closed for the one and open for the other.

The draft and Save

The row doesn't report to you directly. ReceiptsConfig.Threshold hands the ReceiptsThreshold.Root callbacks that write into a draft held here, so a row commit (blur, Enter, a switch flip) moves the draft and nothing else. Save is the only thing that writes.

The PATCH body carries both fields every time. It is a partial update — an omitted field keeps its stored value, or takes a default when no override exists — and since the user can see both controls, sending only the one they touched would let the other fall to a default they never chose.

Its response is the business's config, in the same shape the read returns, so it seeds the read cache directly: the row reseeds from what the server now holds, Save goes inert, and no second GET fires. A failed write keeps the draft so a retry costs no retyping.